INVOTA Platform
API Documentation
Complete REST API reference for the INVOTA e-invoicing platform. All endpoints conform to the FIRS NRS specification for e-invoice generation, signing, and transmission in Nigeria.
Overview
The INVOTA API gives you programmatic access to every part of the e-invoicing lifecycle, from creating a draft to confirming NRS acknowledgement. All requests go to the base URL above over HTTPS.
Authentication
The dashboard API uses bearer token authentication. After logging in, include the token in every subsequent request:
Authorization: Bearer {your-token}The B2B enterprise API uses API key authentication. See Section 8 for details.
Rate Limits
| API Group | Limit | Window |
|---|---|---|
| Dashboard API (all authenticated routes) | 60 requests | Per minute |
| B2B Enterprise API | 100 requests | Per minute |
When a rate limit is exceeded the API returns HTTP 429 with a Retry-After header.
Response Format
All responses are JSON. Successful responses include a data key. Error responses include a message key and, where applicable, an errors key with field-level details.
// Success
{ "data": { ... } }
// Validation error
{
"message": "Validation failed.",
"errors": {
"invoice_number": ["The invoice number field is required."]
}
}Multi-Tenancy
Every authenticated request is automatically scoped to the organisation of the authenticated user. It is not possible to access data belonging to another organisation through this API.
Invoice Status Flow
Invoices progress through the following statuses as they move through the NRS pipeline:
Any stage can transition to failed on NRS rejection. Failed invoices can be retried. They return to draft.
Authentication
All authentication endpoints are public. No token required.
/auth/registerRegisters a new organisation and creates the first user account (the owner). The user receives the finance role with is_owner = true.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| org_name | string | Required | Name of the business |
| tin | string | Required | FIRS Tax Identification Number |
| string | Required | Business email address | |
| password | string | Required | Minimum 8 characters |
| name | string | Required | Full name of the registering user |
| phone | string | Optional | Business phone number |
| address | string | Optional | Business address |
Response: 201 Created
{
"data": {
"token": "1|abcdefghijklmnopqrstuvwxyz",
"user": {
"id": "uuid", "name": "Adaeze Okonkwo",
"email": "adaeze@acme.ng", "role": "finance"
},
"organization": { "id": "uuid", "name": "Acme Nigeria Ltd" }
}
}/auth/loginAuthenticates a user and returns a bearer token.
Request Body
| Field | Type | Required |
|---|---|---|
| string | Required | |
| password | string | Required |
Response: 200 OK
{
"data": {
"token": "2|abcdefghijklmnopqrstuvwxyz",
"user": {
"id": "uuid", "name": "Adaeze Okonkwo",
"email": "adaeze@acme.ng",
"role": "finance", "is_owner": true
}
}
}/auth/logoutRevokes the current bearer token. The token becomes invalid immediately.
Response: 200 OK
{ "data": { "message": "Logged out successfully." } }Invoice Management
All routes require authentication. Write operations require an active subscription. Supplier party details are automatically derived from the authenticated organisation's taxpayer profile.
/invoicesReturns a paginated list of invoices for the authenticated organisation.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| status | string | Filter by: draft, validated, signed, transmitting, transmitted, acknowledged, reported, failed |
| search | string | Search by invoice number or buyer name |
| page | integer | Page number (default: 1) |
Response: 200 OK
{
"data": [
{
"id": "uuid",
"irn": "INV001-2741A890-20260701",
"invoice_number": "INV001",
"issue_date": "2026-07-01",
"status": "signed",
"currency_code": "NGN",
"total_amount": 150000.00,
"vat_amount": 19565.22
}
],
"meta": { "total": 42, "per_page": 15, "current_page": 1, "last_page": 3 }
}/invoicesCreates a new invoice in draft status. Supplier party details are taken from the organisation's taxpayer profile. The IRN is built and validated server-side. Per-line amounts and totals are calculated server-side.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| invoice_number | string | Required | Alphanumeric only. No special characters or spaces. |
| invoice_type_code | string | Required | NRS invoice type code (e.g. 380) |
| issue_date | date | Required | YYYY-MM-DD. Used to build the IRN. |
| currency_code | string | Required | ISO 4217 currency code (e.g. NGN) |
| buyer.name | string | Required | Buyer company or individual name |
| buyer.email | string | Required | Buyer email address |
| buyer.tin | string | Optional | Required for B2B invoices |
| buyer.incorporation_number | string | Optional | Used when buyer TIN is not available |
| buyer.address | string | Optional | |
| lines | array | Required | At least one line item |
| lines[].description | string | Required | |
| lines[].quantity | decimal | Required | |
| lines[].unit_price | decimal | Required | |
| lines[].tax_category_code | string | Required | NRS tax category (e.g. S, Z, E) |
| lines[].product_category | string | Required | goods or services |
| lines[].hsn_code | string | Required for goods | Format: 0000.00 |
| lines[].isic_code | string | Required for services | 4-digit ISIC code |
| note | string | Optional | Stored encrypted |
| payment_terms_note | string | Optional | Stored encrypted |
Response: 201 Created
{
"data": {
"id": "uuid",
"irn": "INV001-2741A890-20260701",
"status": "draft",
"total_amount": 150000.00,
"vat_amount": 19565.22
}
}/invoices/{id}Returns the full details of a single invoice including all line items and party details.
/invoices/{id}Updates a draft invoice. Only allowed when status is draft. Only the account owner (is_owner = true) may edit an invoice. If the invoice number or issue date changes, the IRN is rebuilt and re-validated server-side.
/invoices/{id}Soft-deletes a draft invoice. Only allowed when status is draft. Only the account owner may delete. Deleted invoices are not permanently removed from the database.
/invoices/bulkCreates up to 100 invoices in a single request.
Request Body
{ "invoices": [ { ... }, { ... } ] }Response: 207 Multi-Status
Returns a result for each submitted invoice: success or the specific validation error for that item.
Invoice Lifecycle
These endpoints move an invoice through the NRS submission pipeline. All background communication with NRS runs as queued jobs. The API returns 202 Accepted immediately and processing continues in the background.
/invoices/{id}/submitSubmits a draft invoice to NRS for validation and signing. Dispatches a background job that first validates the invoice against NRS, then signs it and generates the QR code. The invoice status moves from draft through validated to signed if both steps succeed.
Response: 202 Accepted
{ "data": { "message": "Invoice submitted. Processing in background." } }/invoice/confirm/{irn}Polls NRS to confirm the current status of an invoice by its IRN. Use this to check whether a submitted invoice has been signed or to surface any NRS-side issue.
Response: 200 OK
{ "data": { "irn": "...", "status": "signed", "nrs_message": "..." } }/invoices/{id}/transmitTransmits a signed invoice to the NRS exchange network so the buyer's system can receive it. Only available once the invoice status is signed. Runs as a background job.
Response: 202 Accepted
{ "data": { "message": "Invoice queued for transmission." } }/invoices/{id}/paymentUpdates the payment status of an invoice. When status is set to PAID or PARTIAL, the system automatically queues a VAT post-payment report to NRS and sends a receipt email to the buyer.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| payment_status | string | Required | PENDING, PARTIAL, PAID, or REJECTED |
| payment_date | date | Optional | Date payment was received |
| amount_paid | decimal | Optional | Required when status is PARTIAL |
/invoices/{id}/pdfStreams the invoice as a downloadable PDF. Includes the invoice header, supplier and buyer details, line items, tax totals, the IRN, and the QR code image.
Response
Content-Type: application/pdf. File is streamed as a download.
/invoices/{id}/qrReturns a time-limited pre-signed URL to the QR code image in file storage. Only available once the invoice is signed.
Response: 200 OK
{ "data": { "url": "https://storage.invota.ng/qr-codes/org-id/irn.png?token=..." } }/invoices/{id}/emailQueues an email to the buyer containing invoice details and a PDF attachment.
Response: 202 Accepted
{ "data": { "message": "Email queued for delivery." } }Customers
Customers are buyer contacts saved to the organisation's address book. They can be selected when creating an invoice to pre-fill buyer details.
/customersReturns a paginated list of customers for the authenticated organisation.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| search | string | Filter by name or email |
| page | integer | Page number (default: 1) |
/customersCreates a new customer record.
Request Body
| Field | Type | Required |
|---|---|---|
| name | string | Required |
| string | Required | |
| tin | string | Optional |
| phone | string | Optional |
| address | string | Optional |
/customers/{id}Returns the full details of a single customer.
/customers/{id}Updates a customer record. All fields are optional.
/customers/{id}Deletes a customer record.
Items
Items are saved products or services that can be selected when adding lines to an invoice. Each item stores NRS classification codes so they do not need to be entered each time.
/itemsReturns a paginated list of items for the authenticated organisation.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| search | string | Filter by name or description |
| type | string | Filter by goods or services |
| page | integer | Page number (default: 1) |
/itemsCreates a new item.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Required | |
| description | string | Optional | |
| unit_price | decimal | Required | |
| product_category | string | Required | goods or services |
| hsn_code | string | Required for goods | Format: 0000.00 |
| isic_code | string | Required for services | 4-digit ISIC code |
| tax_category_code | string | Required | NRS tax category |
/items/{id}Returns the full details of a single item.
/items/{id}Updates an item record.
/items/{id}Deletes an item record.
Reports
Reporting endpoints provide summary and export data for the authenticated organisation. Requires the auditor or finance role.
/reports/summaryReturns aggregate invoice statistics over a given date range.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| from | date (YYYY-MM-DD) | Start of date range |
| to | date (YYYY-MM-DD) | End of date range |
Response: 200 OK
{
"data": {
"total_invoices": 127,
"total_value": 4500000.00,
"total_vat": 586956.52,
"by_status": {
"draft": 5, "signed": 12,
"acknowledged": 98, "reported": 12, "failed": 0
}
}
}/reports/vatReturns VAT post-payment report records for the authenticated organisation.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| from | date | Start of period |
| to | date | End of period |
| status | string | pending, submitted, failed |
/reports/exportExports a list of invoices as a CSV file for the given date range and optional status filter.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| from | date | Start of period |
| to | date | End of period |
| status | string | Optional filter by invoice status |
| format | string | csv (default) |
Response
Content-Type: text/csv. File is streamed as a download.
B2B Enterprise API
The B2B API is for enterprise clients that connect their ERP or POS systems directly to INVOTA. It uses API key authentication instead of bearer tokens. Clients access this API only. They do not use the web dashboard.
Authentication
Include both headers on every B2B API request:
X-Api-Key: {your-api-key}
X-Api-Secret: {your-api-secret}API credentials are provisioned by a Best Teck Nigeria Limited admin. Clients can rotate their own credentials at any time using the credentials endpoint below.
/b2b/invoicesSubmits a single invoice through the B2B API. Uses the same request body structure as POST /invoices. Immediately dispatches the validate and sign job. Returns 202 with the IRN as a reference for polling.
Response: 202 Accepted
{ "data": { "irn": "INV001-2741A890-20260701", "status": "draft" } }/b2b/invoices/{irn}Returns the current status of an invoice by its IRN. Poll this after submitting to track progress.
Response: 200 OK
{
"data": {
"irn": "INV001-2741A890-20260701",
"status": "signed",
"qr_url": "https://storage.invota.ng/qr-codes/..."
}
}/b2b/invoices/bulkSubmits up to 50 invoices in a single request. Returns a 207 Multi-Status response with a result for each invoice.
Request Body
{ "invoices": [ { ... }, { ... } ] }/b2b/credentialsReturns the current active credential for the authenticated B2B client (key ID and creation date). The actual key and secret values are not returned after initial provisioning.
/b2b/credentials/rotateRotates the B2B API credentials. The old key is deactivated immediately. The new key and secret are returned once only.
Response: 200 OK
{
"data": {
"api_key": "new-key-shown-once",
"api_secret": "new-secret-shown-once"
}
}api_secret is only returned in this response. It is stored encrypted and cannot be retrieved again. Rotate only when you are ready to update your system immediately.Enterprise Dashboard (Account Management)
Everything above is called by your ERP/POS system using theX-Api-Key / X-Api-Secret pair. The endpoints below are different: they use ordinary Bearer token auth (the same login as the regular dashboard) and power the /dashboard/api developer portal a human enterprise user actually logs into to manage their account — viewing usage, rotating keys, switching billing mode, buying credits, and setting a webhook URL. Your integration code should not call these; they are for the person administering the integration, not the integration itself.
/enterprise/summaryOverview stats for the enterprise dashboard home page: submission counts by outcome, the 10 most recent invoices, and the organisation's current billing state.
Response: 200 OK
{
"stats": {
"total_submitted": 812, "validated_count": 790,
"failed_count": 6, "pending_count": 16
},
"billing": {
"mode": "prepaid",
"outstanding_balance": 0,
"credit_limit_ngn": 500000,
"credits_balance": 340,
"plan_slug": "enterprise",
"per_invoice_rate_ngn": 50.00,
"currency": "NGN",
"available_packs": [
{ "id": "100", "credits": 100, "price_ngn": 5000 },
{ "id": "500", "credits": 500, "price_ngn": 22500 }
]
},
"recent_invoices": [ { "id": "uuid", "irn": "...", "status": "signed", "..." : "..." } ],
"webhook_callback_url": "https://erp.example.com/hooks/invota"
}/enterprise/credentialsReturns metadata for the active API credential (environment, created/rotated/revoked timestamps). The key and secret values are never returned here — only at the moment they are created or rotated. Credentials are issued automatically once KYC is approved; if none exist yet, credential is null.
/enterprise/credentials/rotateRotates the active credential within its current environment. The old key stops working immediately. Same one-time-reveal rule as /b2b/credentials/rotate above.
/enterprise/credentials/environmentSwitches between sandbox and production. The environment is encoded in the key prefix itself, so switching issues a brand new key pair rather than relabeling the old one — every credential in the other environment is revoked at the same time, so nothing from the previous environment keeps working afterwards.
Request Body
| Field | Type | Required |
|---|---|---|
| environment | string | Required |
/enterprise/billing/modeSwitches how invoice submissions are billed: payg (Pay As You Go — a running balance invoiced per submission) or prepaid (a credits balance that decreases per submission, topped up manually). Switching to Prepaid is blocked while an outstanding PAYG balance is unpaid.
Request Body
| Field | Type | Required |
|---|---|---|
| mode | string | Required |
/enterprise/billing/pay/initializeStarts a Paystack payment — either clearing an outstanding PAYG balance (purpose: "balance") or buying a prepaid credit pack (purpose: "credits", with a pack_id from the packs listed in GET /enterprise/summary). Returns a Paystack checkout URL to redirect the user to.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| purpose | string | Required | balance or credits |
| pack_id | string | Required if purpose is credits | Must match an available pack |
Response: 200 OK
{ "authorization_url": "https://checkout.paystack.com/...", "reference": "ent_...", "amount_ngn": 5000 }/enterprise/billing/pay/verifyVerifies a Paystack transaction reference after the user returns from checkout and applies it — clearing the balance or crediting the purchased pack onto credits_balance. Safe to call more than once for the same reference; an already-applied payment is reported back without being applied twice.
Request Body
| Field | Type | Required |
|---|---|---|
| reference | string | Required |
/enterprise/webhook-callback-urlSets the URL that receives NRS transmission events for this organisation's invoices (see Section 9). Must be https:// in production.
/enterprise/webhook/verifySends a single synthetic test event to the saved webhook URL right away, so the user can confirm it's reachable before relying on it. This is a one-off reachability check, not a real event — it is not retried and has no connection to the fire-and-forget delivery used for actual invoice events.
Response: 200 OK / 422
{ "verified": true, "reason": "ok", "status_code": 200 }Webhooks
INVOTA receives event notifications from NRS and forwards them to your registered webhook callback URL. Set the callback URL on your organisation record.
NRS Event Receiver
/webhooks/nrsThis endpoint receives event notifications from NRS. It is registered with NRS as the callback URL for all transmission events. Always returns HTTP 200 to acknowledge receipt. Duplicate events are detected using SHA-256 hash checks and ignored automatically.
Events Forwarded to Your Callback URL
| Event | Description |
|---|---|
TRANSMITTING | NRS has received the invoice on the exchange network |
TRANSMITTED | NRS confirms the invoice reached the buyer's access point |
ACKNOWLEDGED | The buyer's system has acknowledged the invoice |
FAILED | NRS has reported a failure for this invoice |
Webhook Payload
{
"event": "TRANSMITTED",
"irn": "INV001-2741A890-20260701",
"timestamp": "2026-07-01T14:30:00Z"
}GET /b2b/invoices/{irn} as a fallback if your endpoint is temporarily unavailable.Reference Data
The platform caches reference data from NRS and refreshes it daily at 02:00 WAT. These lists power the dropdown menus in the invoice form and validate classification codes at submission time.
/reference/{type}Returns the cached list for the given type.
Available Types
| Type | Description |
|---|---|
invoice_types | NRS invoice type codes (e.g. 380 for commercial invoice) |
payment_means | Payment method codes |
tax_categories | VAT and tax category codes (S = Standard, Z = Zero, E = Exempt) |
currencies | ISO 4217 currency codes |
quantity_codes | Unit of measure codes for invoice lines |
hs_codes | Harmonised System codes for goods classification |
services_codes | ISIC codes for services classification |
countries | Country codes and names |
states | Nigerian state codes |
lgas | Nigerian Local Government Areas |
Response: 200 OK
{
"data": [
{ "code": "380", "name": "Commercial Invoice", "resource_type": "invoice_types" },
{ "code": "381", "name": "Credit Note", "resource_type": "invoice_types" }
]
}IRN Format
The Invoice Reference Number (IRN) is constructed by INVOTA as the System Integrator. NRS does not assign it. The platform builds and validates the IRN before saving each invoice.
Structure
{InvoiceNumber}-{ServiceID}-{YYYYMMDD}| Part | Rules | Example |
|---|---|---|
| InvoiceNumber | Alphanumeric characters only. No spaces, dashes, or special characters. | INV001 |
| ServiceID | 8-character alphanumeric NRS-assigned code for the taxpayer. Stored on the organisation record. | 2741A890 |
| YYYYMMDD | Invoice issue date. Must be a valid calendar date. | 20260701 |
Full Example
INV001-2741A890-20260701
IRN with Timestamp (used for NRS signing payload only)
The Unix timestamp is appended only in the cryptographic signing payload sent to NRS. It does not form part of the IRN printed on the invoice or stored in the database.
INV001-2741A890-20260701.1751328000
Uniqueness
No two invoices within the same organisation may share the same IRN. The platform checks for duplicates before saving. Once an IRN has been submitted to NRS and signed it cannot be reused or re-signed under a different invoice.
Error Codes
All errors follow a consistent structure. The HTTP status code indicates the general error type. The message field gives a human-readable explanation.
| HTTP Status | Meaning | Common Cause |
|---|---|---|
400 | Bad Request | Missing required fields, invalid date format, invalid IRN characters |
401 | Unauthorized | Token expired, token revoked, missing Authorization header |
403 | Forbidden | Wrong role, editing an invoice not in draft status, non-owner trying to delete |
404 | Not Found | Invalid invoice ID, cross-tenant access attempt |
409 | Conflict | Duplicate IRN, duplicate invoice number |
422 | Unprocessable Entity | HSN code format wrong, ISIC code not in reference data, invalid invoice type |
429 | Too Many Requests | More than 60 rpm (dashboard) or 100 rpm (B2B) |
500 | Internal Server Error | NRS API unavailable, background job failure |
503 | Service Unavailable | NRS scheduled maintenance or outage |
Validation Error Response
{
"message": "The given data was invalid.",
"errors": {
"invoice_number": ["The invoice number may only contain letters and numbers."],
"lines.0.hsn_code": ["The HSN code must be in the format 0000.00."]
}
}NRS Rejection Response
{
"message": "NRS rejected the invoice.",
"nrs_code": "INV-004",
"nrs_message": "Supplier TIN not found in NRS database."
}KYC & Verification
Business identity verification. NRS invoice submission can be blocked for an organisation until KYC is approved, depending on the platform's current enforcement settings.
/kycReturns the authenticated organisation's overall KYC status plus the state of each individual required document.
Response: 200 OK
{
"kyc_status": "pending",
"documents": [
{
"type": "cac_certificate",
"label": "CAC Certificate of Incorporation",
"required": true,
"status": "approved",
"rejection_reason": null,
"submitted_at": "2026-07-01T09:00:00Z",
"reviewed_at": "2026-07-02T11:00:00Z"
},
{
"type": "directors_id",
"label": "Director's Government ID",
"required": true,
"status": "pending",
"rejection_reason": null,
"submitted_at": "2026-07-01T09:05:00Z",
"reviewed_at": null
}
]
}Overall Status Values
| Status | Meaning |
|---|---|
| not_submitted | No required document has been uploaded yet |
| pending | At least one required document is awaiting review |
| approved | Every required document has been approved |
| rejected | At least one required document was rejected — re-upload it |
Document Types
| Type | Label | Required |
|---|---|---|
| cac_certificate | CAC Certificate of Incorporation | Required |
| directors_id | Director's Government ID | Required |
| proof_of_address | Proof of Business Address | Required |
| tin_certificate | FIRS TIN Certificate | Optional |
/kyc/submitUploads one document for one type. Re-submitting a type that is still pending or was rejected replaces it — an already approved document cannot be overwritten by re-uploading. Send as multipart/form-data, not JSON.
Request Body (multipart/form-data)
| Field | Type | Required | Description |
|---|---|---|---|
| document_type | string | Required | One of the document types above |
| document | file | Required | PDF, JPG or PNG, max 10 MB |
Response: 201 Created
{
"message": "Document submitted for review.",
"document_type": "cac_certificate",
"status": "pending",
"submitted_at": "2026-07-01T09:00:00Z"
}Billing & Subscriptions
Subscription plan billing for ordinary business and practice accounts via Paystack. Not to be confused with Section 8's Enterprise Dashboard billing, which uses a separate Pay As You Go / Prepaid Credits model for API integrators.
/billingReturns the authenticated organisation's current subscription and payment method state.
Response: 200 OK
{
"subscription": {
"plan_slug": "growth",
"plan_name": "Growth",
"status": "active",
"billing_type": "monthly",
"monthly_fee_ngn": 15000,
"invoice_limit": 200,
"invoices_used": 47,
"cycle_start_at": "2026-07-01T00:00:00Z",
"cycle_end_at": "2026-08-01T00:00:00Z",
"next_renewal_at": "2026-08-01T00:00:00Z",
"outstanding_balance": 0,
"gateway": "paystack",
"has_payment_method": true,
"card_last4": "4081",
"card_type": "visa",
"card_expiry": "09/28",
"features": ["Up to 200 invoices/month", "Email support"],
"trial_days": 0,
"is_popular": true
}
}/billing/historyReturns a paginated list of payment events (charges, renewals, failures) for the authenticated organisation, newest first.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| per_page | integer | 5–50, default 10 |
/billing/history/exportDownloads the full payment history as a CSV file.
Response
Content-Type: text/csv. File is streamed as a download.
/billing/initializeStarts a Paystack payment to activate or renew a subscription plan. Returns a checkout URL to redirect the user to. Consent note: activating a plan this way saves the card used and authorises automatic renewal charges each billing cycle until the plan is changed or cancelled — this is disclosed to the user in the activation dialog before they are redirected.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| plan_slug | string | Required | |
| billing_type | string | Required | monthly or yearly |
Response: 200 OK
{
"authorization_url": "https://checkout.paystack.com/...",
"access_code": "...",
"reference": "inv_...",
"amount_ngn": 15000,
"plan_name": "Growth",
"billing_type": "monthly"
}/billing/verifyVerifies a Paystack reference after the user returns from checkout and activates the subscription. Safe to call more than once for the same reference.
Request Body
| Field | Type | Required |
|---|---|---|
| reference | string | Required |
Compliance & Audit Trail
Aggregate compliance reporting and the organisation's own activity trail. Distinct from Section 4's per-invoice VAT post-payment reporting — this is summary and historical view, not a write operation.
/compliance/summaryReturns a compliance score plus NRS submission and VAT reporting statistics for the authenticated organisation. The score is a weighted average: NRS acceptance rate × 0.6 + VAT submission rate × 0.4.
Response: 200 OK
{
"compliance_score": 87,
"nrs_acceptance_rate": 92.5,
"vat_submission_rate": 75.0,
"invoice_stats": { "total": 120, "transmitted": 111, "failed": 2, "pending": 7 },
"vat_stats": { "total": 8, "submitted": 6, "failed": 0, "pending": 2 },
"vat_trend": [
{ "month": "Apr", "submitted": 1, "pending": 0 },
{ "month": "May", "submitted": 2, "pending": 1 }
],
"nrs_submissions": [
{ "irn": "INV045-2741A890-20260701", "status": "acknowledged", "date": "2026-07-01", "amount": 85000.00 }
],
"breakdown": [
{ "label": "Invoices transmitted", "value": 111, "total": 120 },
{ "label": "VAT reports submitted", "value": 6, "total": 8 }
]
}/compliance/exportDownloads the full NRS submission history (IRN, status, taxable/VAT/total amounts) as a CSV file.
/audit-trailReturns the authenticated organisation's own activity trail — every tracked create/update/delete action taken within it, sourced from the platform's immutable audit log. Scoped strictly to the caller's own organisation; there is no way to see another organisation's activity through this endpoint.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| per_page | integer | 5–50, default 10 |
| search | string | Filter by actor name, action, or IP address |
| sort | string | recency (default), last_6_months, or alphabetical |
Response: 200 OK
{
"entries": [
{
"id": "225",
"timestamp": "2026-09-09T13:09:31Z",
"actor_name": "Adaeze Okonkwo",
"action": "invoice.updated",
"action_label": "Invoice Updated",
"action_tone": "neutral",
"target": "Invoice",
"ip_address": "102.89.23.4",
"status": "successful"
}
],
"meta": { "current_page": 1, "last_page": 6, "per_page": 10, "total": 59 }
}