Nigeria Revenue Service e-Invoicing · v1.2
e-Invoicing API Specification
The reference for creating, clearing, and managing electronic invoices on the Taxable platform. It covers the Partner API for third-party integrators, public IRN verification, webhooks, and the audit log.
- Document ID
- TAX-EINV-APISPEC-2026.07-v1.2
- Version
- v1.2
- Date
- 20 July 2026
- Status
- Issued for accreditation review
- Document Owner
- Taxable Platform Engineering
- Source of Truth
- Platform OpenAPI document
- Contact
- www.taxable.ng · hello@taxable.ng
Who this document is for. Partners and system integrators building against Taxable’s e-invoicing Partner API, and technical evaluators assessing the platform as part of NRS System Integrator and Access Point Provider accreditation. It is organised the way a new integrator actually experiences the platform: onboarding first, then authentication, then the full endpoint reference.
1. Overview
The Taxable E-Invoicing API lets a business create invoices, submit them to the Nigeria Revenue Service (NRS) for clearance, and receive back an Invoice Reference Number (IRN) that makes each invoice independently verifiable. Around that core clearance flow, the API provides customer management, invoice lifecycle actions (send, pay, void, credit and debit notes), PDF and signed-document retrieval, purchase (input-side) invoice recording, and a per-period VAT ledger that feeds VAT return prefill.
| Environment | Base URL | Notes |
|---|---|---|
| Production | https://api.taxable.ng | Live NRS clearance; production IRNs |
| Sandbox | https://dev-api.taxable.ng | Full API surface; sandbox IRNs |
The API serves two audiences with two distinct authentication families:
- Partner API (/partner/v1/*) is for third-party integrators. Authenticated with an API key in the x-api-key header. Each key maps to exactly one business.
- First-party API is used by Taxable's own invoicing application and developer console. Authenticated with a platform-issued JWT bearer token, scoped to a single business per request.
There is also one deliberately public, unauthenticated endpoint, GET /nrs/verify/{irn}, so that anyone holding an invoice can verify its authenticity without platform credentials.
What happens when an invoice clears
An invoice is created as a draft, then issued: issuing assigns the invoice number and triggers submission to the NRS clearance gateway. On successful clearance the NRS returns an IRN, the invoice becomes a cleared fiscal document, and a webhook event is dispatched to any registered endpoints. Clearance calls to NRS are retried only on transient failures (HTTP 429, 5xx, 408, and network errors); business errors (400, 401, 403, 404, and 409 duplicates) are terminal and never retried. Every cleared invoice also feeds the business's per-period VAT ledger, which becomes the prefill for its VAT return.
2. Getting started: partner onboarding
Partner onboarding is entirely self-service through the Taxable Developer Console, a hosted portal that fronts the platform API. The console is stateless: it owns no database of its own, and every read and write passes through to the platform API using your own credentials.
1. Sign in. Authentication is passwordless. Enter your email address and the console sends a magic link. The same link both registers a new developer account and signs in an existing one, so there is no separate signup form. The link is verified server-side before any session cookie is set.
2. Select your business and check NRS enrolment. The console home page shows a business selector and the NRS enrolment status of the selected business. NRS enrolment is a precondition for issuing invoices that clear. If the business is not yet enrolled, complete enrolment before attempting your first issue call.
3. Create an API key. Create, list, and revoke Partner API keys for the selected business. Existing keys are always displayed masked.
Keys are shown once
The key value is shown exactly once, at creation. Copy it into your secrets manager immediately, because it cannot be retrieved again. If a key is lost, revoke it and create a new one. This is deliberate: the platform never stores or redisplays the plaintext key.
4. Register a webhook. Register your outbound webhook endpoint URL and choose the event types you want to receive. The signing secret is also shown once, at registration. Store it alongside your API key; you will use it to verify webhook signatures. The webhooks page includes a delivery log with one-click replay of failed deliveries.
5. Make your first call. Passing an invoice payload to POST /partner/v1/invoices creates the invoice; by default it is issued immediately (use ?issue=false to create a draft only).
Create and issue an invoice (sandbox)
curl -X POST "https://dev-api.taxable.ng/partner/v1/invoices" \
-H "x-api-key: $TAXABLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer": {
"name": "Eko Allied Manufacturing Ltd",
"tin": "01234567-0001",
"email": "accounts@ekoallied.ng",
"address": "14 Creek Road, Apapa, Lagos"
},
"issueDate": "2026-07-13",
"dueDate": "2026-08-12",
"currency": "NGN",
"lineItems": [
{
"description": "Industrial packaging film — 500kg roll",
"quantity": 4,
"unitPrice": 185000.00,
"vatRate": 7.5
},
{
"description": "Delivery and handling, Apapa to Ikeja",
"quantity": 1,
"unitPrice": 45000.00,
"vatRate": 7.5
}
]
}'Response: 201 Created
{
"success": true,
"data": {
"id": "inv_01J9ZQ4T8RVXW2M5KD73PA6QNH",
"invoiceNumber": "INV-2026-0147",
"status": "ISSUED",
"irn": "IRN-1784297456123",
"customer": { "name": "Eko Allied Manufacturing Ltd", "tin": "01234567-0001" },
"currency": "NGN",
"subtotal": 785000.00,
"vatAmount": 58875.00,
"total": 843875.00,
"issueDate": "2026-07-13",
"dueDate": "2026-08-12"
}
}Note the sandbox-shaped IRN (IRN-<epoch-ms>). In production the IRN follows the NRS format; see the IRN format appendix.
6. Watch it in the audit log. The console's activity page shows recent Partner API calls made with the selected business's keys: method, path, status, latency, and request ID. See Audit log for exactly what is, and is never, recorded.
7. Optional: bulk import. For high-volume backfills, upload an invoice CSV, watch rows clear via live polling against the batch-status endpoint, and download a per-row result CSV showing success or failure for every line.
3. Authentication
The platform has two authentication families. Which one you use is determined by which API surface you are calling, and they are not interchangeable.
| First-party (internal app) | Partner API | |
|---|---|---|
| Mechanism | Platform-issued JWT, Authorization: Bearer | API key via x-api-key header |
| Scope | One authenticated user, scoped to a single business per request | One key maps to exactly one business |
| Rate limit | Governed by session-level controls | 10 req/s sustained, burst 20, 50,000 requests/month |
| Issued via | Platform sign-in (magic link) | Self-service via the developer console |
| Error shape | { error: { type, code, message } } | { success, data | error } |
Partner API: every /partner/v1/* route requires the key. Keys are attached to an API gateway usage plan, so rate limiting and the monthly quota are enforced at the gateway, before a request reaches application code.
curl "https://api.taxable.ng/partner/v1/invoices?status=ISSUED&limit=20" \
-H "x-api-key: $TAXABLE_API_KEY"First-party calls carry a platform-issued bearer JWT. The authenticated user must hold the OWNER or ACCOUNTANT role on the target business, otherwise the request is rejected with 403.
Key and webhook management is first-party only
A partner cannot create, rotate, or revoke its own API keys through the Partner API. Key and webhook management lives behind bearer authentication and the developer console. This is intentional: a leaked API key cannot be used to mint further keys.
4. Making requests
- Base URLs: production https://api.taxable.ng, sandbox https://dev-api.taxable.ng. Integrate and certify against sandbox first.
- Content type: request and response bodies are JSON; send Content-Type: application/json. The exception is binary document endpoints (invoice PDF).
- Business scoping: Partner API calls are scoped automatically, because the API key identifies the business.
- Monetary units: all monetary values in this API — invoice amounts, tax summaries, and VAT ledger figures — are expressed in document-currency major units, that is naira with decimal kobo (e.g. 185000.00). No minor-unit conversion is applied at any layer.
Rate limits (Partner API), enforced at the API gateway via a usage plan, per key:
| Limit | Value |
|---|---|
| Sustained rate | 10 requests/second |
| Burst | 20 requests |
| Monthly quota | 50,000 requests |
Every Partner API endpoint can return 429 Too Many Requests. Treat 429 as retryable with exponential backoff and jitter.
HTTP/1.1 429 Too Many Requests
{
"success": false,
"error": {
"type": "rate_limited",
"code": "RATE_LIMIT_EXCEEDED",
"message": "Request rate limit exceeded. Retry with backoff."
}
}5. Reading responses
The two API surfaces use deliberately different response envelopes. Match your client's parsing to the surface you call. The Partner API wraps every payload in success / data; the first-party API returns resources directly and uses a bare error object on failure.
Partner API envelope
// Success
{
"success": true,
"data": { "id": "inv_01J9ZQ…", "status": "ISSUED" }
}
// Failure
{
"success": false,
"error": {
"type": "validation_error",
"code": "INVALID_LINE_ITEM",
"message": "lineItems[0].unitPrice must be a positive number"
}
}| Status | Meaning | Typical cause |
|---|---|---|
| 400 | Invalid state | An action the invoice's current lifecycle state does not allow (e.g. paying a voided invoice) |
| 401 | Unauthenticated | Missing or invalid API key / JWT |
| 403 | Forbidden | First-party caller lacks the OWNER / ACCOUNTANT role on the business |
| 404 | Not found | Unknown resource ID, or a resource belonging to another business |
| 422 | Validation error | Request body fails schema validation |
| 429 | Rate limited | Partner rate or monthly quota exceeded |
6. Partner API reference
All endpoints below require the x-api-key header, are scoped to the key's business, and can return 429. Responses use the partner envelope ({ success, data | error }).
Customers. Customers are the counterparties on your invoices. Creating them as first-class records lets you reference them by ID and keeps TIN and contact data consistent across invoices.
/partner/v1/customersCreate a customer.
/partner/v1/customersList customers for the business (paginated).
/partner/v1/customers/searchSearch customers by name, TIN, or email, e.g. ?q=zaria.
/partner/v1/customers/{id}Retrieve one customer by ID.
/partner/v1/customers/{id}Update a customer. Send the fields to change; the response returns the full updated record.
/partner/v1/customers/{id}Delete a customer. Invoices already issued against the customer are unaffected; they retain their own snapshot of the customer details.
Invoices: create, issue, lifecycle.
/partner/v1/invoicesCreate an invoice. By default the invoice is issued immediately (number assigned, NRS clearance triggered). Pass ?issue=false to create a draft only.
/partner/v1/invoicesList invoices, filterable by status and date, e.g. ?status=ISSUED&from=2026-07-01&to=2026-07-31.
/partner/v1/invoices/{id}Retrieve one invoice with full line items, tax summary, and clearance status.
/partner/v1/invoices/{id}Update a draft invoice. Once issued, an invoice is a cleared fiscal document and can no longer be edited; use a credit or debit note to adjust it.
/partner/v1/invoices/{id}/issueIssue a draft: assigns the invoice number and submits the invoice to NRS for clearance. On success the response carries the IRN.
Response: 200
{
"success": true,
"data": {
"id": "inv_01J9ZQ4T8RVXW2M5KD73PA6QNH",
"invoiceNumber": "INV-2026-0147",
"status": "ISSUED",
"irn": "IRN-1784297456123",
"clearedAt": "2026-07-13T10:02:44Z"
}
}/partner/v1/invoices/{id}/sendSend the invoice to the customer (email delivery with the PDF attached).
/partner/v1/invoices/{id}/payRecord payment against the invoice.
/partner/v1/invoices/{id}/voidVoid an invoice. Voiding is terminal; the invoice remains on record and verifiable but is marked void. Lifecycle actions on a voided invoice return 400 with an invalid-state error.
/partner/v1/invoices/{id}/credit-noteIssue a credit note against a cleared invoice: the correct instrument for reducing or reversing an already-cleared amount.
/partner/v1/invoices/{id}/debit-noteIssue a debit note against a cleared invoice, for charging an additional amount related to the original supply.
Documents and clearance status.
/partner/v1/invoices/{id}/pdfDownload the invoice as a PDF. The response body is the binary document (Content-Type: application/pdf), not a JSON envelope.
/partner/v1/invoices/irn/{irn}/signedRetrieve the signed (cleared) invoice document by IRN: the fiscal artefact as cleared by NRS, addressed by its reference number rather than the platform ID.
/partner/v1/transmission/{irn}Check the NRS transmission status for an IRN; use this to track clearance progress and outcomes without polling the invoice itself.
Purchases (input-side invoices).
/partner/v1/purchasesRecord a purchase invoice received from a supplier, so that input VAT is captured in the business's VAT ledger alongside output VAT from sales.
VAT ledger. Every cleared invoice and recorded purchase feeds a per-business, per-period VAT ledger, which is the source for VAT return prefill. Periods use YYYY-MM. All ledger amounts are in naira, consistent with the invoice endpoints.
/partner/v1/vat-ledger/{period}The full ledger for a period: every entry contributing to output and input VAT.
/partner/v1/vat-ledger/{period}/summaryPeriod totals, grouped into output, input, and adjustment positions.
Response: 200
{
"success": true,
"data": {
"period": "2026-06",
"output": {
"standardRated": 550500000.00,
"zeroRated": 0.00,
"exempt": 0.00,
"totalVat": 41287500.00,
"entryCount": 214
},
"input": {
"vatableValue": 124000000.00,
"inputVatPaid": 9300000.00,
"entryCount": 37
},
"adjustments": {
"netAdjustment": 0.00,
"entryCount": 0
}
}
}/partner/v1/vat-ledger/{period}/prefillThe period's figures shaped as a VAT return prefill: the same data the Taxable filing product uses to pre-populate a VAT return.
Resources.
/partner/v1/resources/{resource}Reference data lookups (enumerations and code lists used in invoice payloads), addressed by resource name.
7. Public IRN verification
/nrs/verify/{irn}PUBLIC — no authentication of any kind.
Verify the authenticity of an invoice by its IRN. Anyone holding an invoice — a consumer checking a receipt, an auditor sampling a ledger, a counterparty's accounts team — can confirm that the IRN is genuine and corresponds to a cleared invoice, without needing platform credentials.
curl "https://api.taxable.ng/nrs/verify/INV0147-A1B2C3D4-20260713"This is a trust-and-transparency feature of the platform: the value of an IRN comes precisely from the fact that its validity can be checked by anyone, independently of the parties to the transaction.
8. First-party API
The first-party API is the surface behind Taxable's own invoicing application and developer console. It shares the same OpenAPI document as the Partner API and uses bearer authentication. Each request is scoped to a single business, and the caller must hold the OWNER or ACCOUNTANT role on that business, otherwise the request is rejected with 403.
It covers the following capability families:
| Capability family | Covers |
|---|---|
| E-Invoices | Full invoice lifecycle: create, update, issue, send, pay, void, credit and debit notes, email, PDF download, get/list/search |
| Invoice Reporting | Dashboard KPIs, revenue (CIT prefill), submissions ledger, bulk CSV batches and batch status |
| Customers | Customer records and search |
| VAT Ledger | Period ledger, period summary, and VAT return prefill |
| Settings | E-invoice settings |
| Business | Business profile, NRS enrolment management, partner key lifecycle, webhook registration, and the activity log |
Management capabilities are excluded from the Partner API
NRS enrolment management, partner key lifecycle (create, list masked, revoke), webhook registration and signing-secret management, and the partner-call activity log are reachable only with bearer authentication, through the console or the first-party application. They are deliberately absent from the key-authenticated Partner API surface.
9. Webhooks
Webhooks push invoice lifecycle updates to your systems so you do not have to poll the transmission endpoint. You register an endpoint URL and choose event types in the console's webhooks page.
The following event types are available for subscription:
| Event | Fired when |
|---|---|
| invoice.created | An invoice record is created |
| invoice.issued | A draft is issued and submitted for clearance |
| invoice.cleared | NRS clears the invoice and an IRN is assigned |
| invoice.rejected | NRS rejects the submission |
| invoice.transmitted | The invoice is transmitted to NRS |
| invoice.paid | Payment is recorded against the invoice |
| invoice.voided | The invoice is voided |
| invoice.credit_noted | A credit note is issued against the invoice |
| invoice.debit_noted | A debit note is issued against the invoice |
Signature verification. Each webhook endpoint has a signing secret, shown once at registration. Every delivery is signed with this secret; verify the signature before trusting a payload, and reject deliveries that fail verification.
Delivery, retries, and replay. The console's webhooks page includes a delivery log for your endpoint. Failed deliveries can be replayed with one click, so a transient outage on your side never means silently lost events. Design your handler to be idempotent: between retries and manual replay, the same event can legitimately arrive more than once.
10. Audit log
Every Partner API call made with your keys is recorded and surfaced in the console's activity page. For each call you can see exactly five things:
| Field | Example |
|---|---|
| Method | POST |
| Path | /partner/v1/invoices |
| Status | 201 |
| Latency | 412 ms |
| Request ID | 7f3c9a2e-4b1d-4e8a-9c67-d21f80a5b3e4 |
Request and response bodies are never logged
The activity pipeline is built from API gateway access logs, which capture request metadata only. This is a deliberate privacy and security commitment, not a limitation: your invoice data, customer PII, and payment details never enter the audit pipeline. What you get is a complete, tamper-evident record that a call happened and how it was answered — never what it contained.
Two practical notes: the log covers key-authenticated Partner API calls, so it is the audit trail for your integration's traffic specifically; and the request ID shown is the same ID you can capture from the API response, making the log directly correlatable with your own application logs when raising a support issue.
11. Appendix A: IRN format reference
| Environment | Shape | Example |
|---|---|---|
| Sandbox | IRN-<epoch-ms> | IRN-1784297456123 |
| Production (NRS format) | {InvoiceNo}-{ServiceID}-{YYYYMMDD} | INV0147-A1B2C3D4-20260713 |
Sandbox IRNs are locally generated and exist so the full clearance flow can be exercised end-to-end without touching the live regulator gateway. Production IRNs follow the NRS reference-number format and are verifiable by anyone via GET /nrs/verify/{irn}. The ServiceID segment shown above is illustrative; each accredited provider is assigned its own.
12. Appendix B: Rate limits quick reference
| Surface | Sustained | Burst | Monthly quota | Enforced at |
|---|---|---|---|---|
| Partner API | 10 req/s | 20 | 50,000 requests | API gateway usage plan, per key |
| First-party | Session-level controls | — | — | Application layer |
| Public verify | Unauthenticated public endpoint | — | — | — |
On 429, back off exponentially with jitter. If your integration's steady-state volume approaches the monthly quota, contact Taxable about your usage plan before you hit it; the quota is a gateway-enforced hard stop.
13. Appendix C: Changelog
| Version | Date | Changes |
|---|---|---|
| v1.2 | 20 July 2026 | Published to the web. Stated monetary units definitively as naira across all endpoints, including the VAT ledger. Corrected the VAT ledger period-summary response shape. Documented the subscribable webhook event types. Replaced individual attribution with role-based document ownership. |
| v1.1 | 13 July 2026 | Applied Taxable brand identity; added the document control block and branded footer. |
| v1.0 | 13 July 2026 | Initial publication. |
Taxable E-Invoicing API Specification · TAX-EINV-APISPEC-2026.07-v1.2 · 20 July 2026 · www.taxable.ng · hello@taxable.ng