Introduction
Welcome to the Afrinvoice API documentation. This guide provides all required information for developers integrating with our e-Invoicing platform, including authentication, invoice validation, IRN generation, QR generation, and response formats.
The API follows RESTful principles and accepts and returns data in JSON format. All requests must be authenticated using your Access Key and Access Secret obtained from the authentication endpoint.
Main Capabilities
- Generate IRN (client-side pattern)
- Validate Invoice Payload
- Generate encrypted QR Code (FIRS standard)
- Download & Confirm Invoices
Authentication
Authenticate using email & password to receive access_token and access_secret.
LIVEPOST /api/login
// Login endpoint POST /api/login Content-Type: application/json Authenticate with email + password and receive a token pair used in all requests.
{
"email": "user@example.com",
"password": "yourpassword"
}
{
"status": "success",
"access_token": "YXNkZjEyMzQtYWJjZC01Njc4LWpoazAtc2VjcmV0dG9rZW4=",
"access_secret": "c2VjcmV0LXZhbHVlLWFzZGZhc2RmLWhhbmRsZW1l"
}
| Field | Required | Description |
|---|---|---|
| Yes | User login email | |
| password | Yes | User login password |
curl -X POST "https://your-backend.example.com/api/login" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "yourpassword"
}'
$payload = [ "email" => "user@example.com", "password" => "yourpassword" ]; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://your-backend.example.com/api/login", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => ["Content-Type: application/json"], CURLOPT_POSTFIELDS => json_encode($payload) ]); $response = curl_exec($curl); curl_close($curl); echo $response;
import axios from "axios";
axios.post("https://your-backend.example.com/api/login", {
email: "user@example.com",
password: "yourpassword"
})
.then(res => console.log(res.data))
.catch(err => console.error(err));
import requests
payload = {
"email": "user@example.com",
"password": "yourpassword"
}
res = requests.post(
"https://your-backend.example.com/api/login",
json=payload
)
print(res.json())
System Integrator API Endpoints
Generate IRN
Client-side IRN formation pattern (server only receives the resulting IRN).
LOCALClient: generate IRN string
// IRN format (client-side)
{invoiceNumber}-{FIRS_SERVICE_ID}-{YYYYMMDD}
INV001-SERVICEID-20251005
| Field | Required | Description |
|---|---|---|
| invoiceNumber | Yes | Alphanumeric only (no spaces/special chars) |
| FIRS_SERVICE_ID | Yes | Your assigned service id from FIRS |
| invoiceDate | Yes | YYYY-MM-DD (used to produce YYYYMMDD) |
// Client should produce IRN and send that string to backend endpoints below. // (No server-side call required for generation itself)
Validate Invoice
Validate invoice payload with FIRS via your backend proxy.
POST/api/validate-invoice
{
"business_id": "6389237e-4f6e-4371-aece-aea5d2536df3",
"irn": "INV001-SERVICEID-20251005",
"issue_date": "2025-10-05",
"due_date": "2025-10-05",
"issue_time": "13:45:00",
"invoice_type_code": "396",
"payment_status": "PENDING",
"note": "Optional notes",
"tax_point_date": "2025-10-05",
"document_currency_code": "NGN",
"tax_currency_code": "NGN",
"accounting_cost": "100232 NGN",
"invoice_delivery_period": {
"start_date": "2025-10-05",
"end_date": "2025-10-25"
},
"order_reference": "",
"accounting_supplier_party": {
"party_name": "Supplier Ltd",
"tin": "32492774-0001",
"email": "developer@afrinvoice.com",
"telephone": "+2348026664444",
"postal_address": {
"street_name": "Supplier address",
"city_name": "ANTHONY",
"postal_zone": "100232",
"lga": "70",
"state": "4",
"country": "NG"
}
},
"accounting_customer_party": {
"party_name": "Customer Inc",
"tin": "33577312-0001",
"email": "mark@markodenore.com",
"telephone": "+2348026665555",
"postal_address": {
"street_name": "Customer address",
"city_name": "ANTHONY",
"postal_zone": "100232",
"lga": "70",
"state": "4",
"country": "NG"
}
},
"tax_total": [
{
"tax_amount": 250,
"tax_subtotal": [
{
"taxable_amount": 2500,
"tax_amount": 250,
"tax_category": {
"id": "LOCAL_SALES_TAX",
"percent": 10
}
}
]
}
],
"legal_monetary_total": {
"line_extension_amount": 2500,
"tax_exclusive_amount": 2500,
"tax_inclusive_amount": 2750,
"payable_amount": 2750
},
"invoice_line": [
{
"hsn_code": "CC-001",
"product_category": "Consulting Services",
"discount_rate": 0,
"fee_rate": 10,
"invoiced_quantity": 1,
"line_extension_amount": 2500,
"item": {
"name": "Service A",
"description": "Consulting",
"sellers_item_identification": "item-1"
},
"price": {
"price_amount": 2500,
"base_quantity": 1,
"price_unit": "NGN per 1"
}
}
]
}
{
"message": "FIRS validation successful",
"data": {
"code": 200,
"data": {
"ok": true
}
}
}
| Header | Value / Notes |
|---|---|
| Content-Type | application/json |
| x-api-key | Backend injects when proxying to FIRS (do not expose) |
| x-api-secret | Backend injects when proxying to FIRS (do not expose) |
Top-level required fields: business_id,
irn, issue_date,
invoice_line,
legal_monetary_total.
curl -X POST https://yourdomain.com/api/validate-invoice \
-H "Content-Type: application/json" \
-d '{
"business_id": "6389237e-4f6e-4371-aece-aea5d2536df3",
"irn": "INV123-147-20251012",
"issue_date": "2025-10-12",
"due_date": "2025-10-12",
"issue_time": "12:05:22",
"invoice_type_code": "396",
"payment_status": "PENDING",
"note": "",
"tax_point_date": "2025-10-12",
"document_currency_code": "NGN",
"tax_currency_code": "NGN",
"accounting_cost": "100232 NGN",
"buyer_reference": "",
"invoice_delivery_period": {
"start_date": "2025-10-12",
"end_date": "2025-10-25"
},
"order_reference": "",
"billing_reference": null,
"dispatch_document_reference": null,
"receipt_document_reference": null,
"originator_document_reference": null,
"contract_document_reference": null,
"additional_document_reference": null,
"accounting_supplier_party": {
"party_name": "Business Name",
"tin": "32492774-0001",
"email": "developer@afrinvoice.com",
"telephone": "+2348026664444",
"business_description": "Consulting services",
"postal_address": {
"street_name": "Business Address",
"city_name": "ANTHONY",
"postal_zone": "100232",
"lga": "70",
"state": "4",
"country": "NG"
}
},
"accounting_customer_party": {
"party_name": "Customer Name",
"tin": "33577312-0001",
"email": "mark@markodenore.com",
"telephone": "+2348026665555",
"business_description": null,
"postal_address": {
"street_name": "Customer Address",
"city_name": "ANTHONY",
"postal_zone": "100232",
"lga": "70",
"state": "4",
"country": "NG"
}
},
"payee_party": null,
"bill_party": null,
"ship_party": null,
"tax_representative_party": null,
"actual_delivery_date": "2025-10-12",
"payment_means": null,
"payment_terms_note": null,
"allowance_charge": [
{ "charge_indicator": true, "amount": 800.6 },
{ "charge_indicator": false, "amount": 100.50 }
],
"tax_total": [
{
"tax_amount": 250.00,
"tax_subtotal": [
{
"taxable_amount": 1500.00,
"tax_amount": 250.00,
"tax_category": {
"id": "LOCAL_SALES_TAX",
"percent": 17.5
}
}
]
}
],
"legal_monetary_total": {
"line_extension_amount": 1500.00,
"tax_exclusive_amount": 1400.00,
"tax_inclusive_amount": 1650.00,
"payable_amount": 1650.00
},
"invoice_line": [
{
"hsn_code": "CC-001",
"product_category": "Consulting Services",
"discount_rate": 10,
"discount_amount": 50.00,
"fee_rate": 17.5,
"fee_amount": 87.50,
"invoiced_quantity": 2,
"line_extension_amount": 1000.00,
"item": {
"name": "Product A",
"description": "my wonderful product",
"sellers_item_identification": "item-1"
},
"price": {
"price_amount": 500.00,
"base_quantity": 1,
"price_unit": "NGN per 1"
}
}
]
}'
<?php
$payload = [
"business_id" => "6389237e-4f6e-4371-aece-aea5d2536df3",
"irn" => "INV123-147-20251012",
"issue_date" => "2025-10-12",
"due_date" => "2025-10-12",
"issue_time" => "12:05:22",
"invoice_type_code" => "396",
"payment_status" => "PENDING",
"note" => "",
"tax_point_date" => "2025-10-12",
"document_currency_code" => "NGN",
"tax_currency_code" => "NGN",
"accounting_cost" => "100232 NGN",
"buyer_reference" => "",
"invoice_delivery_period" => [
"start_date" => "2025-10-12",
"end_date" => "2025-10-25"
],
"order_reference" => "",
"billing_reference" => null,
"dispatch_document_reference" => null,
"receipt_document_reference" => null,
"originator_document_reference" => null,
"contract_document_reference" => null,
"additional_document_reference" => null,
"accounting_supplier_party" => [
"party_name" => "Business Name",
"tin" => "32492774-0001",
"email" => "developer@afrinvoice.com",
"telephone" => "+2348026664444",
"business_description" => "Consulting services",
"postal_address" => [
"street_name" => "Business Address",
"city_name" => "ANTHONY",
"postal_zone" => "100232",
"lga" => "70",
"state" => "4",
"country" => "NG"
]
],
"accounting_customer_party" => [
"party_name" => "Customer Name",
"tin" => "33577312-0001",
"email" => "mark@markodenore.com",
"telephone" => "+2348026665555",
"business_description" => null,
"postal_address" => [
"street_name" => "Customer Address",
"city_name" => "ANTHONY",
"postal_zone" => "100232",
"lga" => "70",
"state" => "4",
"country" => "NG"
]
],
"payee_party" => null,
"bill_party" => null,
"ship_party" => null,
"tax_representative_party" => null,
"actual_delivery_date" => "2025-10-12",
"payment_means" => null,
"payment_terms_note" => null,
"allowance_charge" => [
["charge_indicator" => true, "amount" => 800.6],
["charge_indicator" => false, "amount" => 100.50]
],
"tax_total" => [
[
"tax_amount" => 250.00,
"tax_subtotal" => [
[
"taxable_amount" => 1500.00,
"tax_amount" => 250.00,
"tax_category" => [
"id" => "LOCAL_SALES_TAX",
"percent" => 17.5
]
]
]
]
],
"legal_monetary_total" => [
"line_extension_amount" => 1500.00,
"tax_exclusive_amount" => 1400.00,
"tax_inclusive_amount" => 1650.00,
"payable_amount" => 1650.00
],
"invoice_line" => [
[
"hsn_code" => "CC-001",
"product_category" => "Consulting Services",
"discount_rate" => 10,
"discount_amount" => 50.00,
"fee_rate" => 17.5,
"fee_amount" => 87.50,
"invoiced_quantity" => 2,
"line_extension_amount" => 1000.00,
"item" => [
"name" => "Product A",
"description" => "my wonderful product",
"sellers_item_identification" => "item-1"
],
"price" => [
"price_amount" => 500.00,
"base_quantity" => 1,
"price_unit" => "NGN per 1"
]
]
]
];
$ch = curl_init("https://yourdomain.com/api/validate-invoice");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import axios from "axios";
axios.post("https://yourdomain.com/api/validate-invoice", {
business_id: "6389237e-4f6e-4371-aece-aea5d2536df3",
irn: "INV123-147-20251012",
issue_date: "2025-10-12",
due_date: "2025-10-12",
issue_time: "12:05:22",
invoice_type_code: "396",
payment_status: "PENDING",
note: "",
tax_point_date: "2025-10-12",
document_currency_code: "NGN",
tax_currency_code: "NGN",
accounting_cost: "100232 NGN",
buyer_reference: "",
invoice_delivery_period: {
start_date: "2025-10-12",
end_date: "2025-10-25"
},
order_reference: "",
billing_reference: null,
dispatch_document_reference: null,
receipt_document_reference: null,
originator_document_reference: null,
contract_document_reference: null,
additional_document_reference: null,
accounting_supplier_party: {
party_name: "Business Name",
tin: "32492774-0001",
email: "developer@afrinvoice.com",
telephone: "+2348026664444",
business_description: "Consulting services",
postal_address: {
street_name: "Business Address",
city_name: "ANTHONY",
postal_zone: "100232",
lga: "70",
state: "4",
country: "NG"
}
},
accounting_customer_party: {
party_name: "Customer Name",
tin: "33577312-0001",
email: "mark@markodenore.com",
telephone: "+2348026665555",
business_description: null,
postal_address: {
street_name: "Customer Address",
city_name: "ANTHONY",
postal_zone: "100232",
lga: "70",
state: "4",
country: "NG"
}
},
payee_party: null,
bill_party: null,
ship_party: null,
tax_representative_party: null,
actual_delivery_date: "2025-10-12",
payment_means: null,
payment_terms_note: null,
allowance_charge: [
{ charge_indicator: true, amount: 800.6 },
{ charge_indicator: false, amount: 100.50 }
],
tax_total: [
{
tax_amount: 250.0,
tax_subtotal: [
{
taxable_amount: 1500.0,
tax_amount: 250.0,
tax_category: {
id: "LOCAL_SALES_TAX",
percent: 17.5
}
}
]
}
],
legal_monetary_total: {
line_extension_amount: 1500.0,
tax_exclusive_amount: 1400.0,
tax_inclusive_amount: 1650.0,
payable_amount: 1650.0
},
invoice_line: [
{
hsn_code: "CC-001",
product_category: "Consulting Services",
discount_rate: 10,
discount_amount: 50.0,
fee_rate: 17.5,
fee_amount: 87.5,
invoiced_quantity: 2,
line_extension_amount: 1000.0,
item: {
name: "Product A",
description: "my wonderful product",
sellers_item_identification: "item-1"
},
price: {
price_amount: 500.0,
base_quantity: 1,
price_unit: "NGN per 1"
}
}
]
})
.then(res => console.log(res.data))
.catch(err => console.error(err));
import requests
payload = {
"business_id": "6389237e-4f6e-4371-aece-aea5d2536df3",
"irn": "INV123-147-20251012",
"issue_date": "2025-10-12",
"due_date": "2025-10-12",
"issue_time": "12:05:22",
"invoice_type_code": "396",
"payment_status": "PENDING",
"note": "",
"tax_point_date": "2025-10-12",
"document_currency_code": "NGN",
"tax_currency_code": "NGN",
"accounting_cost": "100232 NGN",
"buyer_reference": "",
"invoice_delivery_period": {
"start_date": "2025-10-12",
"end_date": "2025-10-25"
},
"order_reference": "",
"billing_reference": None,
"dispatch_document_reference": None,
"receipt_document_reference": None,
"originator_document_reference": None,
"contract_document_reference": None,
"additional_document_reference": None,
"accounting_supplier_party": {
"party_name": "Business Name",
"tin": "32492774-0001",
"email": "developer@afrinvoice.com",
"telephone": "+2348026664444",
"business_description": "Consulting services",
"postal_address": {
"street_name": "Business Address",
"city_name": "ANTHONY",
"postal_zone": "100232",
"lga": "70",
"state": "4",
"country": "NG"
}
},
"accounting_customer_party": {
"party_name": "Customer Name",
"tin": "33577312-0001",
"email": "mark@markodenore.com",
"telephone": "+2348026665555",
"business_description": None,
"postal_address": {
"street_name": "Customer Address",
"city_name": "ANTHONY",
"postal_zone": "100232",
"lga": "70",
"state": "4",
"country": "NG"
}
},
"payee_party": None,
"bill_party": None,
"ship_party": None,
"tax_representative_party": None,
"actual_delivery_date": "2025-10-12",
"payment_means": None,
"payment_terms_note": None,
"allowance_charge": [
{ "charge_indicator": True, "amount": 800.6 },
{ "charge_indicator": False, "amount": 100.50 }
],
"tax_total": [
{
"tax_amount": 250.00,
"tax_subtotal": [
{
"taxable_amount": 1500.00,
"tax_amount": 250.00,
"tax_category": {
"id": "LOCAL_SALES_TAX",
"percent": 17.5
}
}
]
}
],
"legal_monetary_total": {
"line_extension_amount": 1500.00,
"tax_exclusive_amount": 1400.00,
"tax_inclusive_amount": 1650.00,
"payable_amount": 1650.00
},
"invoice_line": [
{
"hsn_code": "CC-001",
"product_category": "Consulting Services",
"discount_rate": 10,
"discount_amount": 50.00,
"fee_rate": 17.5,
"fee_amount": 87.50,
"invoiced_quantity": 2,
"line_extension_amount": 1000.00,
"item": {
"name": "Product A",
"description": "my wonderful product",
"sellers_item_identification": "item-1"
},
"price": {
"price_amount": 500.00,
"base_quantity": 1,
"price_unit": "NGN per 1"
}
}
]
}
response = requests.post("https://yourdomain.com/api/validate-invoice", json=payload)
print(response.json())
Generate QR Code
Encrypt IRN + server-side timestamp with FIRS public key and return QR image (base64 data URL).
POST/api/generate-qr
{
"irn": "INV001-SERVICEID-20251005"
}
{
"success": true,
"qrCodeDataUrl": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAAAklEQVR4AewaftIAABmaSURBVO3BQY7khrIgQXei7n9lH20IxIYEO5XVT/wTZvYP1lrrBQ7WWuslDtZa6yUO1lrrJQ7WWuslDtZa6yUO1lrrJQ7WWuslDtZa6yUO1lrrJQ7WWuslDtZa6yUO1lrrJQ7WWuslDtZa6yV++BdU/oaKT6lcqZhUpopPqZwq7qicKiaVOxVPqVypmFSuVNxRuVIxqVypmFSmipPKUxWTylRxUpkqJpWp4qRyp+Kk8qmKSWWqOKlMFZPK31DxiYO11nqJg7XWeomDtdZ6iR++qOJbVL6hYlI5qfwJlVPFpPINKncqnlKZKp6quKLyVMVTFZPKVPFUxVMVk8qpYlJ5quKpiknlTsVJ5amKpyq+ReUbDtZa6yUO1lrrJQ7WWuslfvhFKk9VPKUyVXyi4lMqU8VTKlPFSeW3qHyq4lQxqUwVJ5Wp4lMqVyomlanipHKn4qQyVUwqk8qpYlL5VMWVir9B5amK33Cw1lovcbDWWi/xw/8xKlPFVHFF5b+m4lsqTipTxR2VU8UdlVPFnYorFZPKN1TcUbmicqfipDJVTCq/QeVKxZsdrLXWSxystdZLHKy11kv88H+AylMqp4o7FVdU7qhcqZhUrqh8i8oVlTsVVyquqEwVk8o3qNxRearipDJVTCqfqjip3FGZKk4qU8WkclKZKt7kYK21XuJgrbVe4mCttV7ih19U8bdV3Kk4qfwJlacqTirfUvGUylRxUvkTKt+gMlV8g8pU8ZTKb6h4qmJSmSomlSsqU8U3VPyvHay11kscrLXWSxystdZL/PBFKv8LFSeVqWJSOVVMKk9VTCpTxScqJpU7KqeKT1VMKlPFSWWqmFROFZPKFZWpYlKZKp5SOVX8DSpTxaRyqvhUxaRyRWWquKLyX3Ow1lovcbDWWi/xw79Q8V9TMalcUfkTFSeVqWJSOVVMKlPFSeVPVHyiYlK5o3JF5YrKVPGpik9VfKLiTsWk8gmVOypTxZWKT1X8lx2stdZLHKy11kscrLXWS/zwL6hMFZPKN1RMFVdUpopJ5RsqPlVxpWJSmVQ+pXKquFMxqZwqJpVPqZwq7qg8pfIbVL6l4orKVDGpnCq+ReUbKn7DwVprvcTBWmu9xMFaa73ED7+o4qTyJypOKlPFUyr/CxUnlaniUxVXVJ5S+RMVT1U8VXFS+RMVJ5Wp4htUpoqnVCaVb6l4SuVUMalMFSeVqWJSmSpOKlPFNxystdZLHKy11kvYP/gSlacqJpUrFXdUnqp4SmWqOKl8quKKyp2Kp1Smik+pnCruqDxVcUXlqYpJ5UrFpHKlYlL5VMUVlTsVk8onKiaVKxV3VK5UTCpTxScO1lrrJQ7WWuslDtZa6yV++BdUpoqnVO5UfKJiUnlKZaqYVE4VT6k8VTGp3FE5VUwVV1TuVEwVJ5Wp4krFUypTxaTyqYqTyp2Kk8qfqLiicqXiT1R8Q8UVlaniTsWVim84WGutlzhYa62XOFhrrZewf/AhlTsVJ5Wp4o7KqWJSeapiUjlV3FG5UjGpXKm4o3Kl4lMqU8UVlaniisqnKp5SeapiUnmq4imVT1VcUblTMamcKiaVqeKk8lTFn1A5VUwqU8UnDtZa6yUO1lrrJX74Syr+RMWViisqdyqeqriicqfiExWTylQxqZwqpoorKlPFpDJVnComlU+pnCr+RMVJZaqYVE4Vk8pUcVKZKj6l8imVT6lcqZhUrqj8rx2stdZLHKy11kscrLXWS/zwH6FypeKOyjeo3Kk4VdxRearipPInKk4qT1XcqfiGijsVJ5U7FZPKqWJSmSpOKndUThWTylTxqYqTyp2KSeWk8lTFpPJUxR2Vk8pvOFhrrZc4WGutlzhYa62XsH/wIZU7FSeVOxWfUjlVfIvKlYpPqUwVT6lcqXhKZaqYVK5UTCpTxSdUpopJZao4qUwVV1TuVJxU/oaKSeVOxUllqviUypWKp1Smim84WGutlzhYa62XOFhrrZewf/A/oPKpiknlVDGpTBUnlaniKZWnKiaVT1VMKlcqJpWnKp5SeariKZU7FVdUrlRMKlPFFZWpYlK5UnFF5U7FpPINFZPKqWJS+ZaKTxystdZLHKy11kv88ItUrlR8SuWpiknlVDGpPFXxLRUnlT9RcVK5U3FSmSomlSsVU8Wkcqr4VMWkMqmcKqaKSeVKxadUpoqTyqQyVXxDxaTyqYqTylQxqfxtB2ut9RIHa631EgdrrfUSP/wLKlPFVHFSuaPyDSp3Kk4qU8UdladUnlK5UnFH5VQxqXyq4imVKypTxaTyG1S+QeVPqFypmFSeUvlUxRWVp1TuVJxUfsPBWmu9xMFaa73EwVprvcQP/0LFpDJVPFXxKZVTxd+gMlVMFVdUpoqTyh2VKyq/ReVUMVVMKqeKpyruqEwVJ5WnVKaKSeVU8S0qVyruqEwVVyquqEwVv6HiNxystdZLHKy11kv88ItUThV3VJ6quKIyVUwqp4pJZar4lMqp4o7KqWJSmSqeUnlK5U7FSeVOxVMVJ5WpYqqYVE4Vk8pUcVL5lMpUcUVlqvhUxaTyVMUVlaniKZUrFb/hYK21XuJgrbVe4mCttV7C/sGHVO5UnFT+RMUnVP7rKj6lMlVcUXmqYlKZKj6hMlVMKp+quKJypeIplaliUpkqrqhMFSeVP1FxReWpiqdUnqqYVKaKTxystdZLHKy11kscrLXWS9g/+JDKVPEtKr+h4orKVDGpnComlanipHKn4htU7lScVH5LxUllqriicqdiUnmq4imVKxWfUpkqrqhMFZPKlYpJ5RMVk8q3VHziYK21XuJgrbVewv7Bh1SmiisqU8XfoHKl4o7KlYqnVH5LxTeoTBWTypWKKypTxVMqU8UVlTsVJ5Wp4lMqU8VJZaqYVE4Vd1SmipPKnYorKlPFSWWq+F87WGutlzhYa62XOFhrrZewf/AhlacqJpXfUPGUyp2KKypPVUwqU8VJ5bdUXFGZKq6oPFUxqUwVn1L5DRUnlTsVk8qViknlVDGpTBWTyqnijspvqJhUnqr4xMFaa73EwVprvcTBWmu9xA//QsUdlacqnlL5lMqp4o7KVHGqeErlWyqeUrmiMlVMKlPFqWJSmSpOKlPFp1SeqnhK5UrFn6j4hModlaniqYqTylTxlMqkMlWcVKaKbzhYa62XOFhrrZc4WGutl7B/8CGVqWJSeapiUjlVTCpTxUnlUxV3VK5UPKUyVVxRmSomlVPFpHKlYlKZKiaVU8WnVKaKT6lcqZhUThWTyrdU/K+pPFUxqZwqJpWp4imVqeITB2ut9RIHa631Ej/8CxW/peI3VJxUPlUxqTxVMamcKv5ExVMVVyomlaniGyquqPyWiqcqPqXyiYpJZaq4ojJVXFG5U/EbKr7hYK21XuJgrbVe4mCttV7ih7+kYlKZVP4GlVPFpDJVTBUnlaniisq3qHxK5amKSeVUMak8VXGl4o7KUyrfoPItFZPKb1B5SuVTKlcqJpWp4hMHa631EgdrrfUSB2ut9RI//CUqdyp+Q8VvqPiUylTxqYorKlPFSeVPVFypuKJyR+VUMancqbiiMlWcVKaKKxWTylTxDSpTxR2VU8UdlVPFUyp/ouKkMlV8w8Faa73EwVprvYT9g79A5W+omFSeqphUpoqTyp2Kk8pTFX9C5VQxqVypmFSmiknlExWTylMVk8pU8ZTKqWJS+VTF/4LKlYpJ5UrFp1Q+VfGJg7XWeomDtdZ6iYO11nqJH/4FlTsVVyomlanipHKn4qQyVUwq31DxG1SmiknlUxUnlaniqYpJZao4qUwVV1R+S8VJ5amKSWVSmSpOKlPFpPKpipPKpHKlYlL5VMVTKt9wsNZaL3Gw1lovcbDWWi/xwxdVTCqnikllqphUrlRMKqeKOxVXVKaKSeVUMalMFU9VXFG5U/GJikllqpgqrlRMKp+omFSmiisqU8Wkcqq4o/INFZ+quKPyVMU3VEwqU8VvO1hrrZc4WGutlzhYa62X+OFfqLhT8ZTKVHFSuVNxUnmq4o7KUxWTypWKKypTxaTyKZUrFZPKVHFF5VMqT6lMFaeKOxVPVXyDylTxGyq+peKkMqlMFVdUfsPBWmu9xMFaa73ED/+CylQxqVypmFQmladUrlRMKieVOxWTyknlqYq/QeVOxVMVv0FlqnhKZVI5VUwqVyomlSsVn6r4lMqnVK5UTBWTyqniv+ZgrbVe4mCttV7iYK21XuKHL1KZKq6oTBVXVJ6quFPxqYqTyqdUpoorKndUThVPqUwV31JxUrmj8qmKKxVXVO5UnFQ+pfJUxR2VT1V8g8pU8bcdrLXWSxystdZLHKy11kvYP/gSlU9VTCpXKp5SuVJxR2WqeErlSsUVlT9R8ZTKUxWTyqnijsqpYlKZKr5B5U7FFZW/oWJSuVJxR+WpiisqU8VJZaq4o3KqmFSmik8crLXWSxystdZL/PBFFZ9SmSq+oWJSuaJyR+VUMal8SuVKxaQyqZwqPlUxqUwVT1WcVKaKT6lMFZ9QmSo+pTJVXFGZKk4qd1SmiisqT1VcqZhU7lRcqfiGg7XWeomDtdZ6iYO11nqJH/4FlTsVV1SmiknlVPEplanipHKnYlL5BpWnVKaKSeWKylTxKZVPVEwqVyomlaniUyqnikllqjip3KmYVK5UTCqnikllqphUThVPqTxV8SdUnqr4xMFaa73EwVprvcTBWmu9xA//QsUdlU9VnFT+F1SmipPKVDGpXKmYVE4Vk8qnKq6oTBV3Kq6oXFGZKiaVT6k8VfGJikllUrlS8amKSWWqOKk8VTGpXFG5U/GUyjccrLXWSxystdZL2D/4EpUrFZPKUxWTylTxDSpTxaTyiYpJZao4qUwVk8pUcUXlSsWnVJ6qmFSmiisq/wsVV1TuVJxUpopJ5UrFHZVTxR2VKxW/QeVOxScO1lrrJQ7WWuslDtZa6yV++KKKSeVTFSeVOyqnijsqv6HiUyqniknlN6hMFZPKlYpJZao4qUwV31JxReVKxVMqn6qYVJ5SuVPx21SmiknlbztYa62XOFhrrZc4WGutl/jhX1CZKq6o3KmYVP62ikllqriicqXiUxWfqriiMqlMFZPKSeWOyqliUnmqYlK5ovIplSsVk8odld9QcUXlqYrfUnFS+Q0Ha631EgdrrfUSB2ut9RI//EeoTBVPqZxUpopPVUwqp4qp4qmKv0FlqjhVTCp/Q8UVlUnljsqpYlKZKj6hMlXcUTlV3FG5UvGpiqdUnlKZKq5UTCrfcLDWWi9xsNZaL/HDX1IxqdxReariG1SmiqniKZWnKk4qv0XlVPG/oDJVnComlaniisodlacqrqhMFVPFSWWquFIxqUwVVyomlanipPItKlcqfsPBWmu9xMFaa73EwVprvcQP/0LFt1Q8pTKpPFVxUpkq7qhcqfiGikllqnhKZao4qdxRmSquqEwVJ5Wp4lMqT1U8pfIplaniVDGpTBUnlTsqU8VTKlcqnlK5U3FSmSq+4WCttV7iYK21XuJgrbVe4od/QeUplT+hcqq4U3FF5UrFpyomlacqrqj8CZVTxR2VU8UdlUnlKZUrKlcqpoqnVO6onCruqHxK5UrFlYo/oXKq+BaVU8WdiqdUpopPHKy11kscrLXWS/zwRRVXVP5ExSdUnlL5ExUnlaniKZWp4lQxqdypeKripPInKq6oTBUnlaliUrmicqfiqYqnKk4qn6qYVD5VMVVcqbiicqfiKZWp4krFNxystdZLHKy11kscrLXWS9g/+CUqf1vFpDJVPKUyVVxRmSpOKncqTiq/peKkMlXcUTlV3FE5VXyLyn9dxUllqphUrlTcUTlVTCpTxUnlWyomlVPFbzhYa62XOFhrrZc4WGutl/jhP6ripPKpiisqdyomlb+tYlKZKk4qU8WkckVlqpgqPqEyVUwqp4pJ5U7FFZWp4qRyp+KkMlV8S8VJZVKZKn5DxaRyqviUylTxDQdrrfUSB2ut9RI//AsqU8VU8SmVpypOKlPFlYpPVUwqk8qpYlL5DRVPVfwNFZPKVHFS+RMqp4o7KqeKOyqfUrmiMlWcKiaVOxVPqVxReUplqpgqTiqTylTxiYO11nqJg7XWeomDtdZ6iR++SOVbKk4qd1SeUjlVTCpTxVRxUpkqfoPKVHFF5VMqU8UVladUvqViUvnbVO5UPKVyqpgqJpWp4krFpHKqmFSmiisVT1X8hoO11nqJg7XWeomDtdZ6CfsHv0TlSsWk8g0Vk8pTFZPKVPENKlPFSWWquKNypeIplaliUvlExaRypeJTKk9VTCpTxUnlTsUVlaniisqdiisq/3UV33Cw1lovcbDWWi9xsNZaL/HDL6o4qUwqdyquqFxReariUypTxTdU3FGZKk4qd1ROFVPFpDJVnFSmiknlpPKUyp2KKxWTylRxUvm/pGJSmSquqFyp+BMqV1Smik8crLXWSxystdZL2D/4kMpUMamcKu6oXKm4o3Kl4lMqVyomlW+omFTuVHxCZaq4o3Kq+F9QuVIxqUwVT6mcKv6EylMVT6lcqZhUnqr4FpWnKj5xsNZaL3Gw1lovcbDWWi/xw39ExRWVv0FlqphUTipTxaRypWJSOancqfiGikllqpgqTipPVXxK5VtUThV3Kk4qn6q4o/KpipPKnYqTyqTyVMWkMlX8toO11nqJg7XWeomDtdZ6iR/+EpU7FZPKqWJSuVLxWypOKncqTiqTyreonComlacqPlUxqZxUnqr4ExVXKp5SmSqeqphUfkPFpHKqeKpiUnlKZaqYVK5UfMPBWmu9xMFaa72E/YMPqUwVV1Smikllqjip3Kk4qdyp+AaVb6l4SuVvqHhK5amKp1SeqphUpoqTylRxReVOxTeoTBWTypWKp1Smik+pTBVXVKaKTxystdZLHKy11kscrLXWS/zwi1ROFX9C5VTxVMVvUTlV/A0qU8Wk8lTFp1SuVEwqV1SuVHxK5Y7KUypXKiaVpyomlSsqU8UVlU+pTBUnlTsVV1R+w8Faa73EwVprvcTBWmu9hP2DX6JyqvhfUHmq4o7KlYorKlPFpHKl4imVOxVXVJ6q+JTKVPEplVPFpHKlYlJ5quKOyqnijsqVim9ROVVMKk9VfEplqvjEwVprvcTBWmu9xMFaa73ED/+CylQxVVxRmSomlVPFUypTxVMqU8WnVE4Vk8pU8ZTKlYo7KlcqvkXlVPEplaliqniq4qTyKZVvqfiUypWKqeIbVKaKv+1grbVe4mCttV7ih/8IlaniisqVik9V3Kk4qUwqV1TuqDxVMak8VXFSuaMyVXxCZar4lMpUcVL5VMUVlTsV36DyJyqeUnmq4qQyVUwqU8VJ5TccrLXWSxystdZLHKy11kv88EUqU8VJZaqYVCaVKxWTyhWVqeKkMlVMKt9QMalcqfiUyp2KU8WkMlU8pfIbKu6onComladUrlTcUblSMalcqZhUnlKZKp6q+FTFpPLbDtZa6yUO1lrrJQ7WWuslfvgXKj6lMlU8pTJVfIPKVPGUylRxUpkqJpUrKlPFlYpJ5YrKVPGUyp2Kk8qkMlWcVP5ExZWKSeVUcUflpDJVTBVXVO5UnFQ+VTGpTBVPqZwqJpWpYqo4qfyGg7XWeomDtdZ6CfsHH1KZKp5SmSomlVPFpDJVPKVypeKOyqliUpkqTip3Kk4q/wUVk8qpYlL5VMUVlaliUvkNFVdU7lScVKaKSeVUMalMFVdUpopJ5TdUPKUyVXziYK21XuJgrbVe4mCttV7ih3+h4lMVdyqeUrlS8TdUTCqniknlSsWkMlU8pTJVnFSmikllqrhScUVlqriickdlqjipTBVPqVxRmSomlSsVT6n8CZVTxacqnlKZVKaKk8pU8Q0Ha631EgdrrfUSB2ut9RI//Asqf0PFVDGpnCq+RWWqeKriEyp/QuVUcUflVDGpTBWTyqnijsonKiaVb1E5VXxK5Y7KqeKpijsqT6lMFSeVOyqnijsVk8oVlaniEwdrrfUSB2ut9RI/fFHFt6hcUZkqrqhcqfgTKp+omCq+peKpiisVk8pTKlPFSeWOyqliqviWik9U3FG5ojJVXFH5ExVXKj5V8ZTKVHFS+Q0Ha631EgdrrfUSB2ut9RI//CKVpyq+QWWqmFSuqEwVT6lMFVdUrlRMKpPKp1SeqphUrlRMKk9VfErlisqnVJ6q+FTFSeVOxaRyqphUnlL5VMWkcqXiGw7WWuslDtZa6yUO1lrrJX74/5jKHZWp4qQyVVxRmSqeqphU/gaVT1WcVO6onComlTsVJ5U7Fd+gMqlMFVdU/oaKp1S+peKKylTxiYO11nqJg7XWeomDtdZ6iR/+D1D5hoo7KqeKOyrfoHKn4qQyVVxRmSomlanipDJVXKmYVK6o3Km4UvGUyn9BxVMqU8VJZaqYVE4VT1XcUZkqftvBWmu9xMFaa73ED7+o4jdUPKUyVfwGlanipHJH5amKSeVU8SmVqWJSuaJypWKqmFSuVEwqv6FiUrlSMal8SuVKxR2VU8Wk8lTFpPJUxd92sNZaL3Gw1lovcbDWWi9h/+BDKn9DxaQyVZxUpopJ5UrFUypPVUwqVyomlU9VTCpPVVxR+VTFp1SmiqdUThWTylRxUrlTMalcqXhKZaq4ojJVfIPKVPGUyp2KTxystdZLHKy11kscrLXWS9g/WGutFzhYa62XOFhrrZc4WGutlzhYa62XOFhrrZc4WGutlzhYa62XOFhrrZc4WGutlzhYa62XOFhrrZc4WGutlzhYa62X+H8YTSEf0tsjgwAAAABJRU5ErkJggg==",
"encryptedBase64": "o24MzpmIqWG55j97118zzhHvRuV9pSxTsobReMpzqU2hUEeNVmQhUCH92a7yIEDRn+lLvjP5KAQ2Z1R1cZnrE/GRfmM1Jz08N0M9LARUdGQw1oWSTlKQy0FBC3zQaG8mxkdHBaO8DKexH0BISJyFEugVqP6/2nZUtSl3MxB0BO3yncOkSTo8aiLz60abNaV44kZBainwBT89ikN2GTn73VKAd34iBSpmDmHFtvj54g+bDCI+r8ivJO9nT6gPE/QdMUOz6rtCbHWgxu2rvhJfEkk10R178GQxwS6+xfcrS2wW6LmpfPqtUUQDd+oTV6R0yDkmd7iiJhhheyNUHI4uGA==",
"message": "QR generated successfully"
}
| Field | Type | Required | Description |
|---|---|---|---|
| irn | string | Yes | IRN generated by client (server appends timestamp internally) |
Server will append a unix timestamp
(..
curl -X POST "https://your-backend.example.com/api/generate-qr" \
-H "Content-Type: application/json" \
-d '{
"irn": "INV001-SERVICEID-20251005"
}'
$payload = [ "irn" => "INV001-SERVICEID-20251005" ]; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://your-backend.example.com/api/generate-qr", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => ["Content-Type: application/json"], CURLOPT_POSTFIELDS => json_encode($payload) ]); $response = curl_exec($curl); curl_close($curl); echo $response;
import axios from "axios";
const payload = {
irn: "INV001-SERVICEID-20251005"
};
axios
.post("https://your-backend.example.com/api/generate-qr", payload)
.then((res) => console.log(res.data))
.catch((err) => console.error(err));
import requests
payload = {
"irn": "INV001-SERVICEID-20251005"
}
r = requests.post(
"https://your-backend.example.com/api/generate-qr",
json=payload
)
print(r.json())
Error Codes
The API uses conventional HTTP response codes to indicate the success or failure of a request. In general:
- Codes in the
2xxrange indicate success. -
Codes in the
4xxrange indicate client-side errors (e.g., invalid data, missing fields). -
Codes in the
5xxrange indicate server-side errors (contact support if persistent).
| Code | Status | Description |
|---|---|---|
200 |
OK | Request succeeded. Response includes requested data. |
400 |
Bad Request | Malformed JSON, missing required fields, or invalid data format. |
401 |
Unauthorized | Missing or invalid authentication credentials. |
403 |
Forbidden | Your account lacks permission to access this resource. |
404 |
Not Found | The requested endpoint or resource does not exist. |
422 |
Unprocessable Entity | Semantic errors (e.g., IRN format invalid, TIN mismatch, FIRS validation failed). |
500 |
Internal Server Error | An unexpected error occurred on our server. Retry or contact support. |
502/503 |
Service Unavailable | FIRS gateway is temporarily unreachable. Implement retry logic with exponential backoff. |
Error Response Format
{
"status": "error",
"message": "Validation failed: IRN must follow pattern {invoiceNumber}-{SERVICE_ID}-{YYYYMMDD}",
"code": 400
}
Integration Examples
Below are end-to-end examples showing how to authenticate, validate an invoice, and generate a FIRS-compliant QR code.
1. Full Invoice Workflow (cURL)
# Step 1: Login to obtain tokens
curl -X POST https://api.afrinvoice.com/api/login \
-H "Content-Type: application/json" \
-d '{"email":"integrator@example.com","password":"secure123"}'
# Response:
# { "access_token": "abc...", "access_secret": "xyz..." }
# Step 2: Validate invoice
curl -X POST https://api.afrinvoice.com/api/validate-invoice \
-H "Content-Type: application/json" \
-d '{
"business_id": "6389237e-4f6e-4371-aece-aea5d2536df3",
"irn": "INV2025-147-20251123",
"issue_date": "2025-11-23",
"invoice_line": [...],
"legal_monetary_total": {...},
"accounting_supplier_party": {...},
"accounting_customer_party": {...}
}'
# Step 3: Generate QR code
curl -X POST https://api.afrinvoice.com/api/generate-qr \
-H "Content-Type: application/json" \
-d '{"irn":"INV2025-147-20251123"}'
2. Python Integration Snippet
import requests
# Authenticate
auth = requests.post("https://api.afrinvoice.com/api/login", json={
"email": "integrator@example.com",
"password": "secure123"
}).json()
# Validate
invoice_data = { /* full invoice payload as per /validate-invoice spec */ }
validation = requests.post(
"https://api.afrinvoice.com/api/validate-invoice",
json=invoice_data
).json()
if validation.get("data", {}).get("ok"):
# Generate QR
qr = requests.post("https://api.afrinvoice.com/api/generate-qr", json={
"irn": invoice_data["irn"]
}).json()
print("QR Base64:", qr["qrCodeDataUrl"])
{invoiceNumber}-{FIRS_SERVICE_ID}-{YYYYMMDD} before
sending to /validate-invoice.