Data Lookups & Inquiries

Almost every field code used in this documentation - units of measure, currencies, commodity categories, excise duty codes, branch IDs - comes from EFRIS reference data that you query through these lookups. All lookups are POST requests under the same base URL.

Pagination: endpoints marked as paginated accept a request body of:

{
    "pageNo": 1,
    "pageSize": 15 // Max 99 - a value of 100 or more throws an error
}

Endpoint overview

Endpoint Purpose
/test-connection Connectivity check; returns the EFRIS server time (useful for clock-skew debugging)
/login Taxpayer info, device details, and dictionary versions
/refresh-aes-key Fetch a fresh encryption key (valid 24 hours) - normally handled automatically
/sync-dictionary Full system dictionary: rateUnit (units of measure), currencyType, payWay, etc.
/validate-tin Look up any taxpayer by tin or ninBrn (e.g. a buyer for B2B invoices) - defaults to the TIN in the URL when the body is empty
/query-branches All branches with IDs - required for /transfer-stock
/query-exchange-rates All exchange rates (optional issueDate)
/query-single-exchange-rate Rate for one currency. Required: currency (e.g. "USD"); optional issueDate
/query-commodity-categories Full commodity classification tree (for commodityCategoryId / goodsCategoryId)
/query-paginated-commodity-categories Same, paginated. Required: pageNo, pageSize (max 99)
/query-excise-duty All excise duty codes and rates
/query-deemed-projects Valid vatProjectId values for deemed invoices. Optional: commodityCategoryCode
/register-good-or-service See Goods Registration
/query-goods Registered goods (paginated: pageNo, pageSize)
/query-stock-quantity Current stock for a good. Required: goodsId; optional branchId
/query-good-details Full EFRIS record for one good. Required: goodsCode
/query-stock-movement-history Stock in/out/transfer log. Required: pageNo, pageSize, plus at least one of productionBatchNo, invoiceNo, referenceNo
/query-invoices Search fiscalised invoices (filters: invoiceNo, buyerTin, startDate, endDate, referenceNo, ...)
/query-normal-invoices Invoices eligible for a credit note
/invoice-details Retrieve one fiscalised invoice. Required: invoiceNo (the FDN) - use this to recover data if your ERP timed out during submission

The system dictionary

POST/sync-dictionary

No request body. Returns the full EFRIS system dictionary - the source of every value code used elsewhere (units of measure, currencies, payment modes, Incoterms, ...).

Example data (abridged - each list contains many more entries):

{
    "rateUnit": [
        // Units of measure -> measureUnit, pieceMeasureUnit, exciseUnit
        { "value": "101", "name": "per stick" },
        { "value": "102", "name": "per litre" },
        { "value": "103", "name": "per kg" }
    ],
    "currencyType": [
        // Currency codes -> basicInformation.currency
        { "value": "101", "name": "UGX" },
        { "value": "102", "name": "USD" }
    ],
    "payWay": [
        // Payment modes -> payWay[].paymentMode
        { "value": "101", "name": "Credit" },
        { "value": "102", "name": "Cash" }
    ],
    "deliveryTerms": [
        // Incoterms -> basicInformation.deliveryTermsCode (export invoices)
        { "value": "CFR", "name": "Cost and Freight" },
        { "value": "CIF", "name": "Cost Insurance and Freight" }
    ],
    "creditNoteMaximumInvoicingDays": {
        "value": "90", // Credit notes only allowed within this many days of the original invoice
        "name": "Credit Note Maximum Invoicing days"
    },
    "creditNoteValuePercentLimit": {
        "value": "0.6",
        "name": "credit Note Value Percent Limit"
    },
    "format": {
        "dateFormat": "dd/MM/yyyy",
        "timeFormat": "dd/MM/yyyy HH:mm:ss"
    },
    "customsPackUnitList": [
        // Customs units for export goods - each has a validity window
        {
            "value": "101",
            "name": "per stick",
            "validPeriodFrom": "2021/08/17",
            "periodTo": "2021/08/31"
        }
    ],
    "customsPieceUnitList": [
        {
            "value": "101",
            "name": "per stick",
            "validPeriodFrom": "2021/08/17",
            "periodTo": "2021/08/31"
        }
    ],
    "sector": [
        { "code": "123", "name": "Cigarettes", "parentClass": "0", "requiredFill": "0" }
    ]
}
Cache this locally and re-sync when /login reports a new dictionaryVersion - the codes rarely change.

TIN validation

POST/validate-tin

Look up any taxpayer's URA registration profile - e.g. a buyer's legalName before issuing a B2B invoice. Request (body optional - when both fields are omitted, the TIN in the URL is validated instead):

{
    "tin": "1000029771", // The taxpayer to look up
    "ninBrn": "" // Alternative lookup by NIN (individuals) or BRN (companies)
}

Example data:

{
    "taxpayer": {
        "address": "198 NIP BUILDING Nakawa KAMPALA NAKAWA DIVISION BUGOLOBI",
        "businessName": "UGANDA REVENUE AUTHORITY",
        "contactEmail": "services@ura.go.ug",
        "contactNumber": "256778497936",
        "governmentTIN": "0", // "1": government entity, "0": not
        "legalName": "UGANDA REVENUE AUTHORITY",
        "taxpayerStatus": "101",
        "taxpayerType": "202", // 201: Individual, 202: Non-Individual
        "tin": "1000029771"
    }
}

Branches

POST/query-branches

Example data:

[
    {
        "branchId": "206637525568955296",
        "branchName": "Mr. STEPHEN BUNJO"
    },
    {
        "branchId": "206637528324276772",
        "branchName": "ARINAIT AND SONS CO. LIMITED"
    }
]

Exchange rates (all currencies)

POST/query-exchange-rates

Request (body optional - omit issueDate for today's rates):

{
    "issueDate": "2026-07-17" // Optional - format yyyy-MM-dd
}

Example data (one entry per currency):

[
    {
        "currency": "USD",
        "rate": "3700", // 1 USD = 3700 UGX
        "importDutyLevy": "3740.6388",
        "inComeTax": "3740.6388",
        "exportLevy": "3730.6444"
    },
    {
        "currency": "EUR",
        "rate": "4020.5",
        "importDutyLevy": "4060.705",
        "inComeTax": "4060.705",
        "exportLevy": "4050.2"
    }
]

Exchange rate (single currency)

POST/query-single-exchange-rate

Request:

{
    "currency": "USD", // Required - 3-letter code from the currencyType dictionary
    "issueDate": "2026-07-17" // Optional - yyyy-MM-dd; omit for today's rate
}

Example data:

{
    "currency": "USD",
    "rate": "3700", // 1 USD = 3700 UGX - use this for basicInformation.currencyRate
    "importDutyLevy": "3740.6388",
    "inComeTax": "3740.6388",
    "exportLevy": "3730.6444"
}

Commodity categories

POST/query-commodity-categories

No request body. Returns the entire commodity classification tree - thousands of entries. Prefer the paginated variant below for interactive use; use this one only for a full local sync.

Example data:

[
    {
        "commodityCategoryCode": "50202203",
        "parentCode": "50202200",
        "commodityCategoryName": "Bottled water",
        "commodityCategoryLevel": "4", // Tree depth; only leaf nodes can be assigned to goods
        "rate": "0.18", // VAT rate of this category (0.18 = 18%, "-" = exempt)
        "isLeafNode": "101", // 101: Yes (assignable), 102: No (grouping node)
        "serviceMark": "102", // 101: service, 102: goods
        "isZeroRate": "102", // 101: Yes, 102: No
        "zeroRateStartDate": "",
        "zeroRateEndDate": "",
        "isExempt": "102", // 101: Yes, 102: No
        "exemptRateStartDate": "",
        "exemptRateEndDate": "",
        "enableStatusCode": "1", // 1: enabled, 0: disabled
        "exclusion": "2" // 0: Zero-rated, 1: Exempt, 2: No exclusion
    }
]

Commodity categories (paginated)

POST/query-paginated-commodity-categories

Request:

{
    "pageNo": 1,
    "pageSize": 15 // Max 99 - 100+ throws an error
}

Example data:

{
    "page": {
        "pageNo": "1",
        "pageSize": "15",
        "totalSize": "8213", // Total records
        "pageCount": "548" // Total pages
    },
    "records": [
        {
            "commodityCategoryCode": "50202203",
            "parentCode": "50202200",
            "commodityCategoryName": "Bottled water",
            "commodityCategoryLevel": "4",
            "rate": "0.18",
            "isLeafNode": "101", // 101: Yes, 102: No
            "serviceMark": "102", // 101: service, 102: goods
            "isZeroRate": "102",
            "zeroRateStartDate": "",
            "zeroRateEndDate": "",
            "isExempt": "102",
            "exemptRateStartDate": "",
            "exemptRateEndDate": "",
            "enableStatusCode": "1", // 1: enabled, 0: disabled
            "exclusion": "2", // 0: Zero, 1: Exempt, 2: No exclusion, 3: Both 0% & '-'
            "excisable": "101", // 101: attracts excise duty, 102: does not
            "vatOutScopeCode": "102" // VAT out of scope - 101: Yes, 102: No
        }
    ]
}

Excise duty codes

POST/query-excise-duty

Example data:

{
    "exciseDutyList": [
        {
            "id": "000023",
            "exciseDutyCode": "LED190400",
            "goodService": "Mineral Water",
            "parentCode": "LED190000",
            "rateText": "shs.150.00 Per litre",
            "isLeafNode": "1",
            "effectiveDate": "19/02/2025",
            "exciseDutyDetailsList": [
                {
                    "exciseDutyId": "000023",
                    "type": "102", // 101: Percentage, 102: Unit of measurement
                    "rate": "150",
                    "unit": "102", // Empty when type = 101; rateUnit code when type = 102
                    "currency": "101"
                }
            ]
        }
    ]
}
type maps to exciseRule on invoices: 101 → rule "1" (percentage), 102 → rule "2" (per unit). Codes with type: "102" are the ones requiring havePieceUnit: "101" at registration - see Good Registration, scenario D.

Deemed VAT projects

POST/query-deemed-projects

The TIN is taken from the URL automatically. Request (body optional):

{
    "commodityCategoryCode": "50202203" // Optional filter; multiple codes separated by commas
}

Example data:

{
    "taxpayerType": "103", // 101: normal, 102: exempt, 103: deemed, 104: both deemed & exempt
    "exemptType": "101", // 101: VAT, 102: Excise Duty, 103: both (only present for exempt taxpayers)
    "commodityCategory": [
        {
            "commodityCategoryCode": "50202203",
            "commodityCategoryTaxpayerType": "103" // Same codes as taxpayerType
        }
    ],
    "deemedAndExemptProjectList": [
        {
            "projectId": "893997229738400343", // -> goodsDetails[].vatProjectId
            "projectName": "Kampala Water Project", // -> goodsDetails[].vatProjectName
            "deemedExemptCode": "101", // 101: Strategic Investor, 102: Petroleum Licensee, 103: Aid funded project Contractor, 104: Government MDA, 105: VAT & Excise Duty Exempt, 106: Excise Duty Exempt, 107: Mining Licensee, 108: EACOP Licensee, 109: EACOP Level 1 Contractor
            "commodityCategoryCode": "50202203",
            "serviceMark": "102", // 101: service, 102: goods
            "unit": "101", // rateUnit dictionary
            "currentQty": "100",
            "currentAmount": "100",
            "currency": "USD",
            "exchangeRateDate": "2026-06-12",
            "currentAmountCurrency": "100"
        }
    ]
}
Use projectId / projectName as vatProjectId / vatProjectName on deemed invoice lines - see Fiscal Invoices, scenario E.

Stuck on an integration step? Our engineers reply fast.