FIRS E-Invoicing
FIRS E-Invoicing Platform — Technical & API Documentation
Overview
The Interswitch FIRS E-Invoicing Platform facilitates the secure validation, signing, transmission, and reconciliation of sales invoices between taxpayers and the Federal Inland Revenue Service (FIRS). It supports both administrative and client-facing functions, exposes secure APIs for integration, and provides a 2-factor authentication (2FA) enabled web application for system interaction.
Core Components
Web API
The API layer is built on .NET with OAuth 2.0 authentication and role-based authorization.
Token Generation
Endpoint: POST /Api/SwitchTax/Token
{
"ClientId": "TEST001",
"ClientSecret": "RTR56457%4k"
}Sales Data API
Validates IRN format, invoice payload against schema, digitally signs the invoice, stores the signed version for audit, and transmits to FIRS.
Endpoint: POST /Api/SwitchTax/postInvoice
Sales Invoice Status Update API
Updates invoice status and exposes the updated status.
Endpoint: PATCH /api/v1/invoice/update/{TEST_IRN}
Webhook Endpoint
Receives invoice status events, sends acknowledgment, and updates the system.
Web Application
A secure, 2FA-enabled portal for admins and clients.
Admin View
- Taxpayer Onboarding
- Posted Invoices
- FIRS Resources
- Developer Console
- Email Templates
- User Roles
Client View
- Profile
- Posted Invoices
- FIRS Resources
- Developer Console
- Reports
ERP/Accounting Software Customization
To facilitate seamless transmission of invoice data from an ERP/Accounting system to FIRS, the following customizations are required:
3.1 Mapping VAT Codes to FIRS Tax Categories
FIRS provides a standardized list of tax categories. Existing VAT/tax codes in the ERP must be mapped to these categories to ensure the correct tax type is included in the invoice payload.
3.2 Capturing Corporate Customer Tax Information
Corporate customer master data must capture the following fields:
- Tax Identification Number (TIN)
- Email Address
- Phone Number
3.3 API Call Integration
When an invoice is posted in the ERP system:
- Invoice data is fetched automatically at posting time.
- Data is converted to JSON and transmitted to the e-invoicing sales endpoint.
- The middleware will:
- Validate the Invoice Reference Number (IRN)
- Validate invoice data against the FIRS schema
- Digitally sign the invoice
- Transmit the invoice to FIRS
- A response containing a QR Code is returned to the ERP for record-keeping and printing.
3.4 Invoice Printout Redesign
The invoice printout template must be redesigned to include the QR Code returned by FIRS to ensure all invoices are verifiable and compliant.
Data Flow Summary
- Onboarding: Admin generates Client ID/Secret and shares with taxpayer.
- Invoice Submission: Client submits invoices — validated, signed, and transmitted to FIRS.
- Status Updates: FIRS sends status events to the webhook; system updates and notifies all parties.
Security & Compliance
| Feature | Detail |
|---|---|
| Authentication | OAuth 2.0 with role-based access |
| Login Security | 2FA enabled for all logins |
| Data in Transit | TLS 1.3 |
| Data at Rest | Database encryption |
| Audit | Full logging of all API calls and actions |
| Compliance | FIRS regulations and Nigerian data protection laws |
API Reference
Authentication
Token Generation
POST /Api/SwitchTax/Token
Request
{
"ClientId": "TEST001",
"ClientSecret": "RTR56457%4k"
}Response
{
"Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 3600
}Use the returned Token as a Bearer Token in the Authorization header for all subsequent requests.
Post Invoice
POST /Api/SwitchTax/postInvoice
Invoice Header Fields
| Field | Name | Type | Required | Max Length |
|---|---|---|---|---|
business_id | Business ID (UUID) | String | Yes | 36 |
irn | Invoice Reference Number | String | Yes | 50 |
invoice_kind | Invoice Nature (B2B, B2C, B2G) | String | No | 3 |
issue_date | Invoice Issue Date | Date (YYYY-MM-DD) | Yes | 10 |
due_date | Invoice Due Date | Date (YYYY-MM-DD) | Yes | 10 |
issue_time | Invoice Issue Time | Time (HH:mm:ss) | Yes | 8 |
invoice_type_code | Invoice Type Code | String | Yes | 10 |
tax_point_date | Tax Point Date | Date (YYYY-MM-DD) | Yes | 10 |
document_currency_code | Document Currency Code | String | Yes | 3 |
tax_currency_code | Tax Currency Code | String | Yes | 3 |
billing_reference.irn | Original Invoice IRN (credit note only) | String | Yes | 50 |
billing_reference.issue_date | Original Invoice Issue Date (credit note only) | Time (HH:mm:ss) | Yes | 8 |
Supplier Party Fields (accounting_supplier_party)
accounting_supplier_party)| Field | Name | Type | Required | Max Length |
|---|---|---|---|---|
party_name | Supplier Name | String | Yes | 100 |
tin | Supplier TIN | String | Yes | 20 |
email | Supplier Email | String | Yes | 100 |
telephone | Supplier Telephone | String | Yes | 20 |
business_description | Business Description | String | No | 255 |
postal_address.street_name | Street Name | String | Yes | 150 |
postal_address.city_name | City Name | String | Yes | 100 |
postal_address.postal_zone | Postal Code | String | No | 20 |
postal_address.country | Country Code | String | Yes | 2 |
Customer Party Fields (accounting_customer_party)
accounting_customer_party)| Field | Name | Type | Required | Max Length |
|---|---|---|---|---|
party_name | Customer Name | String | Yes | 100 |
tin | Customer TIN | String | Yes | 20 |
email | Customer Email | String | Yes | 100 |
telephone | Customer Telephone | String | Yes | 20 |
business_description | Business Description | String | No | 255 |
postal_address.street_name | Street Name | String | No | 150 |
postal_address.city_name | City Name | String | Yes | 100 |
postal_address.postal_zone | Postal Code | String | No | 20 |
postal_address.country | Country Code | String | Yes | 2 |
Invoice Line Fields (invoice_line[])
invoice_line[])| Field | Name | Type | Required |
|---|---|---|---|
hsn_code | HSN Code | String | Yes |
product_category | Product Category | String | Yes |
discount_rate | Discount Rate | Decimal | No |
discount_amount | Discount Amount | Decimal | No |
fee_rate | Fee Rate | Decimal | No |
fee_amount | Fee Amount | Decimal | No |
invoiced_quantity | Invoiced Quantity | Decimal | Yes |
line_extension_amount | Line Extension Amount | Decimal | Yes |
item.name | Item Name | String | Yes |
item.description | Item Description | String | No |
item.sellers_item_identification | Item ID | String | Yes |
price.price_amount | Price Amount | Decimal | Yes |
price.base_quantity | Base Quantity | Decimal | Yes |
price.price_unit | Price Unit | String | Yes |
Tax Total Fields (tax_total[])
tax_total[])| Field | Name | Type | Required |
|---|---|---|---|
tax_amount | Total Tax Amount | Decimal | Yes |
tax_subtotal[].taxable_amount | Taxable Amount | Decimal | Yes |
tax_subtotal[].tax_amount | Tax Amount | Decimal | Yes |
tax_subtotal[].tax_category.id | Tax Category ID | String | Yes |
tax_subtotal[].tax_category.percent | Tax Rate (%) | Decimal | Yes |
Legal Monetary Total Fields (legal_monetary_total)
legal_monetary_total)| Field | Name | Type | Required |
|---|---|---|---|
line_extension_amount | Line Extension Total | Decimal | Yes |
tax_exclusive_amount | Tax Exclusive Total | Decimal | Yes |
tax_inclusive_amount | Tax Inclusive Total | Decimal | Yes |
payable_amount | Payable Amount | Decimal | Yes |
Sample Invoice Request
{
"business_id": "1c6eaf77-d0bd-455c-9c5c-500a3f1dbfb2",
"irn": "NISW007611-6AFCD0BD-20250901",
"invoice_kind": "B2B",
"issue_date": "2025-09-01",
"due_date": "2025-09-01",
"issue_time": "13:34:34",
"invoice_type_code": "396",
"tax_point_date": "2025-09-01",
"document_currency_code": "NGN",
"tax_currency_code": "NGN",
"accounting_supplier_party": {
"party_name": "NG",
"tin": "15631438-0242",
"email": "[email protected]",
"telephone": "+23416283888",
"business_description": "Financial technology services",
"postal_address": {
"street_name": "Oko-Awo Street, Victoria Island",
"city_name": "Lagos",
"postal_zone": "80164",
"country": "NG"
}
},
"accounting_customer_party": {
"party_name": "Sterling Bank Plc",
"tin": "15631438-0242",
"email": "[email protected]",
"telephone": "+254712034397",
"business_description": null,
"postal_address": {
"street_name": "",
"city_name": "Victoria Island",
"postal_zone": "",
"country": "NG"
}
},
"invoice_line": [
{
"hsn_code": "2TG27",
"product_category": "3D Secure Monthly Acquiring Fee",
"discount_rate": 0.00,
"discount_amount": 0.00,
"fee_rate": 0.0,
"fee_amount": 0.0,
"invoiced_quantity": 10.00,
"line_extension_amount": 35000.00,
"item": {
"name": "3D Secure Monthly Acquiring Fee",
"description": "10.00 Each at 3500.00 each",
"sellers_item_identification": "2TG27"
},
"price": {
"price_amount": 3500.00,
"base_quantity": 1,
"price_unit": "NGN per Each"
}
},
{
"hsn_code": "1CD02",
"product_category": "CollegePAY",
"discount_rate": 0.00,
"discount_amount": 0.00,
"fee_rate": 0.0,
"fee_amount": 0.0,
"invoiced_quantity": 3.00,
"line_extension_amount": 12000.00,
"item": {
"name": "CollegePAY",
"description": "3.00 Each at 4000.00 each",
"sellers_item_identification": "1CD02"
},
"price": {
"price_amount": 4000.00,
"base_quantity": 1,
"price_unit": "NGN per Each"
}
}
],
"tax_total": [
{
"tax_amount": 2625.00,
"tax_subtotal": [
{
"taxable_amount": 35000.00,
"tax_amount": 2625.00,
"tax_category": {
"id": "STANDARD_VAT",
"percent": 7.50
}
},
{
"taxable_amount": 12000.00,
"tax_amount": 0.00,
"tax_category": {
"id": "ZERO_VAT",
"percent": 0.00
}
}
]
}
],
"legal_monetary_total": {
"line_extension_amount": 47000.00,
"tax_exclusive_amount": 47000.00,
"tax_inclusive_amount": 49625.00,
"payable_amount": 49625.00
}
}Sample Credit Note Request
Same structure as an invoice, with the addition of billing_reference to link to the original invoice:
{
"business_id": "1c6eaf77-d0bd-455c-9c5c-500a3f1dbfb2",
"irn": "NISW007611-6AFCD0BD-20250901",
"invoice_kind": "B2B",
"issue_date": "2025-09-01",
"billing_reference": [
{
"irn": "ITW001-E9E0C0D3-20250619",
"issue_date": "2025-05-14"
}
],
"..." : "...remaining fields same as invoice..."
}Post Invoice Response
{
"code": 201,
"message": "Transmitted successfully",
"data": {
"IRN": "NISW-008634-6AFCD0BD-20251014",
"PostingDateTime": "2025-10-19 22:28:24",
"QRCodeData": "UkXGoG5AWjj..."
}
}Update Invoice Status
POST /UpdateStatus
Request
{
"payment_status": "PAID",
"reference": "payment_reference_or_note",
"irn": "NISW008608-6AFCD0BD-20250930"
}Response
{
"invoiceId": "INV-2025-001",
"status": "ACCEPTED",
"timestamp": "2025-07-01T12:00:00Z"
}Transmit Invoice
POST /transmit/{IRN}
Response
{
"code": 200,
"data": {
"ok": true
}
}Post Queued Invoices
Transmits previously queued invoices for a given TIN within a date range.
Request
{
"tin": "15631438-0242",
"startDate": "2025-05-01",
"endDate": "2025-12-31"
}Response
{
"code": "200",
"message": "Transmitted successfully",
"InvoicesPosted": [
{
"IRN": "ITW005-6AFCD0BD-20250730",
"PostingDateTime": "2025-11-17 21:04:34",
"QRCodeData": "Z4QjuUDN8CY..."
},
{
"IRN": "ITW009-6AFCD0BD-20250730",
"PostingDateTime": "2025-11-17 21:04:34",
"QRCodeData": "PiiEpggiZF0..."
}
]
}Error Handling
All errors follow a standard structured format.
Invalid Token — 401 Unauthorized
401 Unauthorized{
"error": "invalid_token",
"error_description": "The access token is invalid or has expired."
}Missing Required Field — 400 Bad Request
400 Bad Request{
"errorCode": "400",
"errorMessage": "Validation Failed",
"details": "CustomerTIN is required."
}Schema Validation Failed — 422 Unprocessable Entity
422 Unprocessable Entity{
"errorCode": "422",
"errorMessage": "Schema validation failed",
"details": "InvoiceDate must be in YYYY-MM-DD format."
}Internal Server Error — 500
500{
"errorCode": "500",
"errorMessage": "An unexpected error occurred. Please try again later.",
"supportId": "b7f4c7d2-82f3-4a3e-b9f5-0a12345xyz"
}Duplicate IRN — 400
400{
"code": 400,
"data": null,
"message": "error has occurred",
"error": {
"id": "96b4a6dc-ab2c-403e-adec-8a4c0200d87e",
"handler": "invoice_actions",
"details": "unable to complete this operation at this time, kindly try again later",
"public_message": "validation failed: we are unable to process your request. also confirm this is not a duplicate request"
}
}Invalid Business ID — 400
400{
"code": 400,
"data": null,
"message": "error has occurred",
"error": {
"id": "d64ba7c8-e62e-4b3a-aa55-12f49226fcad",
"handler": "invoice_actions",
"details": "invalid UUID length: 35",
"public_message": "validation failed: we are unable to process your request. also confirm this is not a duplicate request"
}
}Invalid Tax Category — 400
400{
"code": 400,
"data": null,
"message": "error has occurred",
"error": {
"id": "a4f0d39d-5780-492f-9f0d-e11cc6acfad2",
"handler": "invoice_actions",
"details": "invoicerequest.invoice.taxtotal[0].taxsubtotal[0].taxcategory.id must be a valid tax category, refer to the invoice resource apis",
"public_message": "validation failed: we are unable to process your request. also confirm this is not a duplicate request"
}
}Invalid Tax Point Date — 400
400{
"code": 400,
"data": null,
"message": "error has occurred",
"error": {
"id": "bbeaab9c-6a28-4ca6-b2fe-9bb82406f01a",
"handler": "invoice_actions",
"details": "invoicerequest.invoice.taxpointdate must be a valid date value yyyy-mm-dd (e.g: 2024-04-29)",
"public_message": "validation failed: we are unable to process your request. also confirm this is not a duplicate request"
}
}Invalid Country Code — 400
400{
"code": 400,
"data": null,
"message": "error has occurred",
"error": {
"id": "2b2775ae-1b7b-4fb7-9124-dcac8e670996",
"handler": "invoice_actions",
"details": "invoicerequest.invoice.accountingsupplierparty.postaladdress.country must be a valid country code, refer to the invoice resource apis",
"public_message": "validation failed: we are unable to process your request. also confirm this is not a duplicate request"
}
}Invalid TIN — 400
400{
"code": 400,
"data": null,
"message": "error has occurred",
"error": {
"id": "8172fe11-e6b7-4c10-af5c-57d3a920a832",
"handler": "invoice_actions",
"details": "invoicerequest.invoice.accountingcustomerparty.tin must be at least in length or value 5",
"public_message": "validation failed: we are unable to process your request. also confirm this is not a duplicate request"
}
}Queued Invoice Errors
Invalid TIN
{
"code": "400",
"message": "Invalid TIN"
}No Queued Invoices
{
"code": "400",
"message": "There are no queued invoices pending to be transmitted"
}FIRS Not Reachable
{
"code": "500",
"message": "FIRS system is currently offline. Please try again later"
}HTTP Status Code Reference
| Status Code | Meaning | Typical Scenarios |
|---|---|---|
200 OK | Request successful | Invoice submitted, status updated, token generated |
201 Created | Resource successfully created | New invoice or client record created |
400 Bad Request | Invalid input provided | Missing required field, malformed JSON |
401 Unauthorized | Authentication failed | Invalid or expired access token |
403 Forbidden | Access denied | Client lacks permission for the resource |
404 Not Found | Resource not found | Invalid endpoint or record not found |
422 Unprocessable Entity | Validation failed | Schema or business rule validation error |
429 Too Many Requests | Rate limit exceeded | Client exceeded request quota |
500 Internal Server Error | Unexpected server error | Unhandled exception, service error |
503 Service Unavailable | Service temporarily unavailable | Scheduled downtime or overload |
Updated about 4 hours ago