# FiducaHub NRS E-Invoicing Third-Party Integration Flow

This guide is for ERP, fintech, POS, SME, and accounting platforms integrating with the Nigeria Revenue Service e-invoicing system through FiducaHub.

FiducaHub is the central API layer. Third parties authenticate with FiducaHub, call FiducaHub endpoints, and let FiducaHub enforce tenant access, taxpayer consent, audit logging, usage metering, idempotency, and controlled upstream NRS/FIRS communication.

## Golden Path

```mermaid
sequenceDiagram
    participant Client as Third-party platform
    participant FH as FiducaHub API
    participant NRS as NRS/FIRS upstream

    Client->>FH: POST /oauth/token
    FH-->>Client: FiducaHub access_token
    Client->>FH: POST /api/v1/utilities/authenticate
    FH->>NRS: Verify taxpayer credentials
    NRS-->>FH: NRS-scoped taxpayer token/status
    FH-->>Client: Taxpayer verification response
    Client->>FH: GET /api/v1/entity/{id}
    FH->>NRS: Resolve entity
    FH-->>Client: business_id, tin, irn_template
    Client->>FH: GET /api/v1/invoice/resources/{type}
    FH-->>Client: Reference data
    Client->>FH: POST /api/v1/utilities/irn/generate
    FH-->>Client: IRN
    Client->>FH: POST /api/v1/invoice/irn/validate
    FH->>NRS: Validate IRN
    FH-->>Client: IRN validation result
    Client->>FH: POST /api/v1/invoice/validate
    FH->>NRS: Validate invoice
    FH-->>Client: Payload validation result
    Client->>FH: POST /api/v1/invoice/sign
    FH->>NRS: Sign invoice
    FH-->>Client: signed_invoice, irn, ack_no, raw upstream QR
    Client->>FH: GET /api/v1/invoice/qrcode/{irn}
    FH-->>Client: FiducaHub regulatory QR
    Client->>FH: POST /api/v1/invoice/transmit/{irn}
    FH->>NRS: Transmit signed invoice
    FH-->>Client: Transmission result
    Client->>FH: GET /api/v1/invoice/transmit/lookup/{irn}
    FH-->>Client: Transmission status
```

## Authentication Model

There are two separate authentication concepts.

| Purpose | Endpoint | Use this token for |
|---------|----------|--------------------|
| FiducaHub API access | `POST /oauth/token` or `POST /auth/user/login` | Calling FiducaHub `/api/v1/*` endpoints through `Authorization: Bearer <access_token>` |
| NRS taxpayer verification | `POST /api/v1/utilities/authenticate` | Verifying taxpayer credentials with upstream NRS/FIRS only |

Do not use the token or status returned by `/api/v1/utilities/authenticate` as the FiducaHub API Bearer token.

## Required Headers

| Header | Required | Notes |
|--------|----------|-------|
| `Authorization: Bearer <access_token>` | Yes | Required for all protected `/api/v1/*` endpoints |
| `Content-Type: application/json` | Yes | Required for JSON request bodies |
| `Accept: application/json` | Recommended | Use JSON unless XML passthrough is explicitly needed |
| `Idempotency-Key` | Yes for writes | Unique per logical write request, 8-128 characters |
| `X-Correlation-Id` | Recommended | Client-generated UUID for end-to-end tracing |

## Step-by-Step Flow

### 1. Get FiducaHub Credentials

Tenant credentials are provisioned by the FiducaHub operator or Admin API.

You need:

- `client_id`
- `client_secret`
- Sandbox base URL
- Taxpayer test credentials
- NRS entity ID or pre-provisioned business identifier

Never expose `client_secret` in browser frontend code.

### 2. Exchange Credentials for a FiducaHub Token

```http
POST /oauth/token
Content-Type: application/json

{
  "grant_type": "client_credentials",
  "client_id": "{{client_id}}",
  "client_secret": "{{client_secret}}"
}
```

Response:

```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

Store `access_token` and send it on every protected request.

### 3. Verify Taxpayer with NRS

```http
POST /api/v1/utilities/authenticate
Authorization: Bearer {{access_token}}
Content-Type: application/json

{
  "email": "{{taxpayer_email}}",
  "password": "{{taxpayer_password}}"
}
```

This confirms upstream taxpayer access. It does not replace the FiducaHub Bearer token.

### 4. Resolve Entity and Business Identifiers

```http
GET /api/v1/entity/{{test_entity_id}}
Authorization: Bearer {{access_token}}
Accept: application/json
```

Capture:

- `business_id`
- `tin`
- `irn_template`, when returned

Use these values when generating IRNs and building invoice payloads.

### 5. Load Reference Data

```http
GET /api/v1/invoice/resources/countries
GET /api/v1/invoice/resources/currencies
GET /api/v1/invoice/resources/tax-categories
GET /api/v1/invoice/resources/payment-means
GET /api/v1/invoice/resources/invoice-types
GET /api/v1/invoice/resources/services-codes
GET /api/v1/invoice/resources/vat-exemptions
GET /api/v1/invoice/resources/hs-codes
```

Use reference data to map country, currency, tax, service, product, payment, and invoice type codes before sending invoice payloads.

For **product lines**, always derive `invoice_line[]` from `GET /api/v1/invoice/resources/hs-codes` (`hscode`, `description`, optional `item`). Map `product_category`, `item.name`, and `item.description` from the catalog entry; use a seller SKU for `sellers_item_identification` (not the HSN code).

### 6. Generate or Validate IRN

Generate an IRN locally through FiducaHub when needed:

```http
POST /api/v1/utilities/irn/generate
Authorization: Bearer {{access_token}}
Content-Type: application/json

{
  "invoice_number": "INV20260001",
  "service_id": "SERV1234",
  "date_stamp": "20260511"
}
```

Validate the IRN before invoice validation/signing:

```http
POST /api/v1/invoice/irn/validate
Authorization: Bearer {{access_token}}
Content-Type: application/json
Idempotency-Key: irn-validate-INV20260001

{
  "business_id": "{{business_id}}",
  "irn": "{{irn}}",
  "invoice_reference": "INV20260001"
}
```

### 7. Validate Invoice Payload

```http
POST /api/v1/invoice/validate
Authorization: Bearer {{access_token}}
Content-Type: application/json
Idempotency-Key: invoice-validate-INV20260001

{
  "business_id": "{{business_id}}",
  "irn": "{{irn}}",
  "issue_date": "2026-05-11",
  "due_date": "2026-05-11",
  "invoice_type_code": "396",
  "document_currency_code": "NGN",
  "tax_currency_code": "NGN",
  "accounting_supplier_party": {
    "party_name": "Supplier Ltd",
    "tin": "{{test_tin}}"
  },
  "accounting_customer_party": {
    "party_name": "Customer Ltd",
    "tin": "9876543210001"
  },
  "legal_monetary_total": {
    "line_extension_amount": 1000,
    "tax_exclusive_amount": 1000,
    "tax_inclusive_amount": 1075,
    "payable_amount": 1075
  },
  "invoice_line": [
    {
      "hsn_code": "0601.10",
      "product_category": "Plants, live",
      "invoiced_quantity": 1,
      "line_extension_amount": 1000,
      "item": {
        "name": "Plants, live",
        "description": "Plants, live; bulbs, tubers, tuberous roots, corms, crowns and rhizomes, dormant",
        "sellers_item_identification": "SKU-001-plants-live"
      },
      "price": { "price_amount": 1000, "base_quantity": 1 }
    }
  ]
}
```

### 8. Sign Invoice

```http
POST /api/v1/invoice/sign
Authorization: Bearer {{access_token}}
Content-Type: application/json
Idempotency-Key: invoice-sign-INV20260001

{
  "...": "Use the same validated invoice payload"
}
```

Capture:

- `irn`
- `ack_no`
- `ack_dt`
- `signed_invoice`
- `qr_code` from upstream NRS response, for raw traceability only

`POST /api/v1/invoice/sign` is the gate for post-sign operations. Do not call download, update, confirm, QR, transmit, or lookup until signing succeeds.

### 9. Generate Regulatory QR and Download Invoice

Use FiducaHub QR for regulatory display:

```http
GET /api/v1/invoice/qrcode/{{irn}}
Authorization: Bearer {{access_token}}
Accept: application/json
```

Response includes:

```json
{
  "data_url": "data:image/png;base64,...",
  "encrypted_payload": "base64-ciphertext",
  "qr_text": "base64-ciphertext",
  "signed_jwt": "optional"
}
```

Download PDF:

```http
GET /api/v1/invoice/download/{{irn}}
Authorization: Bearer {{access_token}}
Accept: application/pdf
```

### 10. Update, Confirm, Search, Transmit, and Lookup

Update payment state:

```http
PATCH /api/v1/invoice/update/{{irn}}
Authorization: Bearer {{access_token}}
Content-Type: application/json
Idempotency-Key: invoice-update-INV20260001

{
  "payment_status": "PAID",
  "payment_date": "2026-05-11",
  "payment_reference": "PAY-2026-0001"
}
```

Confirm invoice:

```http
GET /api/v1/invoice/confirm/{{irn}}
Authorization: Bearer {{access_token}}
```

Search by business:

```http
GET /api/v1/invoice/{{business_id}}?irn={{irn}}&page=1&size=20
Authorization: Bearer {{access_token}}
```

Transmit signed invoice:

```http
POST /api/v1/invoice/transmit/{{irn}}
Authorization: Bearer {{access_token}}
Idempotency-Key: invoice-transmit-INV20260001
```

Lookup transmission:

```http
GET /api/v1/invoice/transmit/lookup/{{irn}}
Authorization: Bearer {{access_token}}
```

## Dependency Rules

- Platform token must exist before all `/api/v1/*` calls.
- NRS taxpayer verification should run before sandbox invoice operations.
- Entity lookup should happen before invoice construction so `business_id`, `tin`, and `irn_template` are available.
- IRN generation/validation happens before invoice validation.
- Invoice validation happens before signing.
- Successful signing gates QR generation, download, update, confirm, search, transmit, and lookup.
- Use the signed or confirmed IRN for post-sign operations.

## Idempotency and Retry Rules

- Send `Idempotency-Key` on write operations.
- Use a fresh key per logical write action.
- Reuse the same key only when retrying the exact same request body.
- If you receive `409 IDEMPOTENCY_CONFLICT`, stop and generate a new key only after confirming this is a new business action.
- Retry `401` once after refreshing the FiducaHub token.
- Retry `429`, `503`, and `504` with exponential backoff.
- Do not automatically retry validation errors or NRS rejection responses without changing the payload.

## Sandbox Checklist

- [ ] Sandbox `baseURL` configured.
- [ ] `client_id` and `client_secret` configured in a secure environment.
- [ ] FiducaHub token request succeeds.
- [ ] Taxpayer verification succeeds or expected sandbox rejection is understood.
- [ ] Entity lookup returns `business_id` and `tin`.
- [ ] Reference data endpoints return expected code lists.
- [ ] IRN is generated or derived from entity template.
- [ ] IRN validation succeeds.
- [ ] Invoice validation succeeds.
- [ ] Invoice signing returns `irn` and `signed_invoice`.
- [ ] QR endpoint returns `data_url` and `encrypted_payload`.
- [ ] Download endpoint returns PDF or expected upstream fallback.
- [ ] Transmit and lookup responses are recorded.
- [ ] Test evidence is exported from Postman or the integration runner without secrets.

## Postman Assets

Import these files into Postman:

- `docs/postman/FiducaHub_NRS_EInvoice.postman_collection.json`
- `docs/postman/FiducaHub_NRS_Sandbox.postman_environment.json`

The collection captures `access_token`, `business_id`, `test_tin`, `irn`, `ack_no`, and `signed_invoice` as it runs.

Before sharing exported run results, remove environment secrets and taxpayer passwords.
