Taxpayers

List Taxpayers

GET /v1/system-integrators/taxpayers

List taxpayers you've registered or synced with the FIRS system.

Field Type Required Description
search string No Filter by name, TIN, or email
per_page integer No Items per page (default: 15)
json
{
  "success": true,
  "message": "Success",
  "data": {
    "data": [ { "...": "Taxpayer object — see Get Taxpayer" } ],
    "current_page": 1,
    "per_page": 15,
    "total": 1,
    "last_page": 1
  }
}

Create Taxpayer

POST /v1/system-integrators/taxpayers

Register a new taxpayer to be synced or managed through the FIRS integration system. The taxpayer is automatically scoped to your System Integrator account.

Field Type Required Description
name string Yes Registered business or taxpayer name
email string Yes Taxpayer's business email address (must be unique)
tin_no string Yes Taxpayer Identification Number issued by FIRS (max 20 chars, must be unique)
phone string No Taxpayer business phone number
nature_of_business string No Brief description of the business activity (max 500 chars)
firs_service_id string Yes FIRS service identifier — exactly 8 hexadecimal characters, must be unique
firs_business_id string Yes FIRS business ID — must be a valid UUID, must be unique
address string Yes Taxpayer business address
contact_person object Yes first_name, last_name, email (all required); phone (optional); password (optional — see note below)
The top-level email is the taxpayer's own business email, distinct from contact_person.email (the contact person's email, used for their login account). If you omit contact_person.password, the created contact account gets a system default password; pass your own if you plan to let that contact log in directly.
json
{
  "name": "Dangote Group",
  "email": "info@dangote.com",
  "tin_no": "TIN-000001",
  "phone": "+23480254099000",
  "address": "32 Owonikoko Street, Gwarinpa, Abuja",
  "nature_of_business": "Cement and building materials supplier",
  "firs_service_id": "94ND90NR",
  "firs_business_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "contact_person": {
    "first_name": "John",
    "last_name": "Doe",
    "email": "johndoe@gemspaysolution.com",
    "phone": "+2348012345678"
  }
}
json
{
  "success": true,
  "message": "Taxpayer created successfully",
  "data": {
    "id": 5,
    "name": "Dangote Group",
    "email": "info@dangote.com",
    "tin_no": "TIN-000001",
    "address": "32 Owonikoko Street, Gwarinpa, Abuja",
    "nature_of_business": "Cement and building materials supplier",
    "firs_business_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "firs_service_id": "94ND90NR",
    "created_at": "2026-08-27T09:00:00.000000Z",
    "updated_at": "2026-08-27T09:00:00.000000Z"
  }
}
This response returns the raw taxpayer record (field name tin_no), which differs slightly from Get Taxpayer's response shape (field name tin) below.

Get Taxpayer

GET /v1/system-integrators/taxpayers/{id}

Retrieve details of a specific taxpayer you own.

Field Type Required Description
id integer (path) Yes Taxpayer's portal ID
json
{
  "success": true,
  "message": "Success",
  "data": {
    "id": 1,
    "name": "Dangote Group",
    "tin": "TIN-000001",
    "email": "info@dangote.com",
    "nature_of_business": "Cement and building materials supplier",
    "firs_service_id": "94ND90NR",
    "firs_business_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "address": "32 Owonikoko Street, Gwarinpa, Abuja",
    "created_at": "2026-08-27 09:00:00",
    "updated_at": "2026-08-27 09:00:00",
    "users": [ { "...": "Contact person(s) attached to this taxpayer" } ]
  }
}

Returns 404 with {"success": false, "message": "Taxpayer not found"} if the taxpayer doesn't exist or belongs to a different System Integrator.

GET /v1/system-integrators/taxpayers/{id}/integration/setup is also available and currently returns this same taxpayer object — it's not a separate ERP-configuration read. Use Update Webhook to configure where this taxpayer's event notifications are delivered.

Update Webhook

PATCH /v1/system-integrators/taxpayers/{id}/webhook

Set or update where a taxpayer's webhook notifications are delivered, and which events are sent.

Field Type Required Description
id integer (path) Yes Taxpayer's portal ID
webhook_url string Yes A valid URL, max 500 characters
enabled_events array No Event names to subscribe to — see the Webhooks page for the current catalog. Omit this key to leave existing events untouched; send an empty array to clear all events

The first call for a taxpayer creates its integration record with sensible defaults (no auth, REST delivery) and activates it; a later call updates the URL/events without disturbing any ERP-specific auth/credentials configured elsewhere.

json
{
  "webhook_url": "https://erp.example.com/webhooks/invoice",
  "enabled_events": ["invoice.status-updated", "payment.status-updated"]
}
json
{
  "success": true,
  "message": "Webhook updated successfully",
  "data": {
    "id": 3,
    "taxpayer_id": 1,
    "webhook_url": "https://erp.example.com/webhooks/invoice",
    "enabled_events": ["invoice.status-updated", "payment.status-updated"],
    "is_active": true
  }
}

Test Webhook

POST /v1/system-integrators/taxpayers/{id}/webhook/test

Send a test notification to a taxpayer's configured webhook URL, to confirm it's reachable before relying on real events.

Field Type Required Description
id integer (path) Yes Taxpayer's portal ID

No request body. Returns 422 if the taxpayer has no webhook configured yet — call Update Webhook first.

json
{
  "success": true,
  "message": "Connection test successful! Response code: 200",
  "data": { "...": "Whatever your endpoint returned" }
}

Rotate Taxpayer API Key

POST /v1/system-integrators/taxpayers/{id}/api-key/rotate

Generate a new tpk_ API key for a taxpayer, invalidating their previous key.

Field Type Required Description
id integer (path) Yes Taxpayer's portal ID

No request body.

json
{
  "success": true,
  "message": "API key rotated successfully. Store this key now - it will not be shown again via this endpoint.",
  "data": {
    "taxpayer_id": 1,
    "api_key": "tpk_9f2c1a8b7e4d6f0a2c5e8b1d4a7c0f3e"
  }
}
The plaintext key is only ever returned in this response — it's stored encrypted and cannot be retrieved again afterward. If it's lost, rotate again to issue a new one.

Continue As

Choose your account type to proceed

Don't have an account? Sign up here