Invoices

Validate Invoice

POST /v1/app/invoices/validate

Checks an invoice payload against the FIRS schema to confirm it's ready for submission, without submitting it.

Field Type Required Description
business_id uuid Yes FIRS business ID — must be a valid UUID
irn string Yes Invoice Reference Number
issue_date date Yes
due_date date Yes Must be on or after issue_date
invoice_type_code string Yes FIRS invoice type code
tax_point_date date Yes Date VAT becomes due
document_currency_code / tax_currency_code string Yes 3-letter currency codes — both required here
order_reference string No
accounting_supplier_party object Yes party_name, tin, email, telephone (all required, no format check); postal_address {street_name, city_name, country (2-letter)} required, postal_zone optional
accounting_customer_party object No Same shape as supplier party, but telephone is optional here
payment_means array Yes payment_means_code, payment_due_date — min 1
tax_total array Yes tax_amount, tax_subtotal[] {taxable_amount, tax_amount, tax_category {id, percent}} — min 1
legal_monetary_total object Yes line_extension_amount, tax_exclusive_amount, tax_inclusive_amount, payable_amount
invoice_line array Yes hsn_code, product_category, invoiced_quantity, line_extension_amount, item {name}, price {price_amount, base_quantity, price_unit (max 3 chars, must exist in Invoice Quantity Codes)} — min 1

Returns 200 on a valid payload, or 400 with the validation failure message.

Submit Invoice

POST /v1/app/invoices/submit

Validates, signs, and submits an invoice to FIRS in one call. Internally this runs through several FIRS steps (IRN validation, data validation, signing, confirmation) — the call is safe to retry with the same irn if it fails partway through; already-completed steps are skipped on retry.

Field Type Required Description
invoice_reference string Yes Your invoice reference
business_id string Yes FIRS business ID
irn string Yes Invoice Reference Number
issue_date date Yes
due_date date No
issue_time string No
invoice_type_code string Yes FIRS invoice type code
payment_status string No PENDING, PAID, or CANCELLED
tax_point_date date No
document_currency_code string Yes 3-letter currency code
tax_currency_code string No
accounting_cost number No
buyer_reference string No
invoice_category string Yes B2C, B2B, or B2G
accounting_supplier_party object Yes party_name, tin, email required; telephone optional (regex: +[6-15 digits] if present); postal_address {street_name, city_name, postal_zone, country (2-letter)} — all required
accounting_customer_party object Conditional Required unless invoice_category is B2C. Same shape as supplier party; telephone optional
legal_monetary_total object Yes line_extension_amount, tax_exclusive_amount, tax_inclusive_amount, payable_amount
invoice_line array Yes hsn_code, product_category, invoiced_quantity, line_extension_amount, item, price — min 1
Also accepted: note, invoice_delivery_period, billing_reference, document references, tax_total, payment_means, payment_terms_note, and allowance_charge — same shape as Create Invoice (Full). Each invoice_line also accepts discount_rate/discount_amount and fee_rate/fee_amount, and item.description and price.price_unit are required (price_unit max 3 chars, must exist in Invoice Quantity Codes).
json
{
  "invoice_reference": "ITW20853450",
  "business_id": "72e9b677-d3d1-41dd-a526-9b5546b863b8",
  "irn": "ITW20853450-6997D6BB-20240703",
  "issue_date": "2024-05-14",
  "invoice_type_code": "396",
  "document_currency_code": "NGN",
  "invoice_category": "B2B",
  "accounting_supplier_party": {
    "party_name": "Dangote Group",
    "tin": "TIN-000001",
    "email": "info@dangote.com",
    "postal_address": { "street_name": "32, Owonikoko Street", "city_name": "Gwarikpa", "postal_zone": "023401", "country": "NG" }
  },
  "accounting_customer_party": {
    "party_name": "Acme Corp Ltd",
    "tin": "TIN-000002",
    "email": "finance@acme.ng",
    "postal_address": { "street_name": "5 Industrial Avenue", "city_name": "Abuja", "postal_zone": "900001", "country": "NG" }
  },
  "legal_monetary_total": {
    "line_extension_amount": 340.50,
    "tax_exclusive_amount": 340.50,
    "tax_inclusive_amount": 366.04,
    "payable_amount": 366.04
  },
  "invoice_line": [
    {
      "hsn_code": "CC-001",
      "product_category": "Food and Beverages",
      "invoiced_quantity": 15,
      "line_extension_amount": 340.50,
      "item": { "name": "item name", "description": "item description" },
      "price": { "price_amount": 22.70, "base_quantity": 1, "price_unit": "C62" }
    }
  ]
}
json
{
  "success": true,
  "message": { "...": "The submission result is currently returned in this field, not in \"data\" — see the note below" },
  "data": "Invoice submitted successfully"
}
This endpoint's response currently has message and data swapped — the submission result object is returned under message, and the literal string "Invoice submitted successfully" is returned under data. Read the payload from message until this is corrected.

Transmit Invoice

POST /v1/app/invoices/transmit

Transmits a previously submitted invoice to FIRS. Before transmitting, this runs a system health check and confirms both the supplier's and customer's access points are online — if either check fails, transmission is rejected without contacting FIRS's transmit endpoint.

Field Type Required Description
irn string Yes The IRN to transmit
json
{ "irn": "INV001-9ES2AR5C-20251007" }

Failures (health-check down, an access point offline, or FIRS rejecting the transmission) return 500 with a descriptive message.

Confirm Transmission Receipt

PATCH /v1/app/invoices/transmit/{irn}/confirm-receipt

Confirms that a transmitted invoice was received.

Field Type Required Description
irn string (path) Yes Invoice IRN
json
{
  "success": true,
  "message": "Invoice transmission receipt confirmed",
  "data": { "...": "Confirmation result" }
}

A receipt that's already been confirmed once returns FIRS's own idempotency message (e.g. "this invoice transmission has been acknowledged by you before") rather than reprocessing it.

Report Invoice

POST /v1/app/invoices/report

Reports an invoice to FIRS for VAT fiscalization — a separate FIRS pipeline from validate/submit/transmit.

Field Type Required Description
agent_tin string Yes TIN of the reporting agent (max 50 chars)
beneficiary_tin string Yes TIN of the invoice beneficiary (max 50 chars)
irn string Yes Invoice Reference Number (max 100 chars)
currency string Yes 3-letter ISO currency code
item_description string Yes Description of invoice items (max 255 chars)
transaction_date date Yes
base_amount number Yes Base amount before VAT
other_taxes number No Any additional taxes
vat_rate number Yes VAT rate percentage
vat_calculated number Yes Calculated VAT amount
total_amount number Yes Total invoice amount
integrator_service_id string Yes Integrator or service provider ID (max 100 chars)
vat_status string Yes STANDARD_VAT, EXEMPT, NON_VATABLE, or ZERO_RATED
json
{
  "agent_tin": "29039239-0001",
  "beneficiary_tin": "29334238-0001",
  "irn": "INV001-E9E0C0D3-20240619",
  "currency": "NGN",
  "item_description": "Items",
  "transaction_date": "2024-11-18",
  "base_amount": 100000,
  "vat_rate": 7.5,
  "vat_calculated": 7500,
  "total_amount": 112500,
  "integrator_service_id": "772392",
  "vat_status": "STANDARD_VAT"
}
json
{
  "success": true,
  "message": "Invoice reported successfully",
  "data": {
    "invoice_number": "INV-2024-001",
    "ok": true,
    "irn": "ITW001-CD8BDCE9-20240703"
  }
}

A failed report currently surfaces as 500 rather than the documented error envelope — check the message field either way for the underlying FIRS error.

Update Payment Status

PATCH /v1/app/invoices/{irn}/update-payment-status
Field Type Required Description
irn string (path) Yes Invoice IRN
payment_status string Yes PAID, PENDING, or REJECTED
remark string No Reason for the update (max 255 chars)
This endpoint's payment_status values (PAID, PENDING, REJECTED) are a different set from Submit Invoice's payment_status field (PENDING, PAID, CANCELLED) — they're not interchangeable.
json
{ "payment_status": "REJECTED", "remark": "Customer rejected the invoice" }

Confirm Invoice

GET /v1/app/invoices/{irn}/confirm

Confirms the current transmission/delivery status of an invoice.

json
{
  "success": true,
  "message": "Invoice confirmed successfully",
  "data": {
    "issue_date": "2024-05-14",
    "due_date": "2024-05-14",
    "sync_date": "2024-05-14",
    "payment_status": "PENDING",
    "transmitted": true,
    "delivered": false
  }
}

Download Invoice

GET /v1/app/invoices/{irn}/download

Download a previously submitted invoice — the full FIRS invoice document, decrypted server-side.

Field Type Required Description
irn string (path) Yes Invoice IRN
json
{
  "success": true,
  "message": "Success",
  "data": {
    "business_id": "24ea0738-dce9-4199-aff0-3fc0181787e2",
    "irn": "GEMSP002-CD8BDCE9-20240703",
    "payment_status": "PENDING",
    "issue_date": "2024-05-14",
    "issue_time": "17:59:04",
    "due_date": "2024-06-14",
    "invoice_type_code": "396",
    "document_currency_code": "NGN",
    "tax_currency_code": "NGN",
    "accounting_supplier_party": { "...": "Party object" },
    "accounting_customer_party": { "...": "Party object" },
    "legal_monetary_total": { "line_extension_amount": 340.5, "tax_exclusive_amount": 400, "tax_inclusive_amount": 430, "payable_amount": 430 },
    "invoice_line": [ { "...": "Line item, same shape as submitted" } ]
  }
}

Returns 404 with {"success": false, "message": "Invoice File not found"} if the invoice hasn't been signed yet.

Continue As

Choose your account type to proceed

Don't have an account? Sign up here