Numbers / Receivables / Invoices
Batch-ingest receivables invoices and drive their commit/void lifecycle.
/v1/numbers-receivables-invoices
/v1/numbers-receivables-invoices/{id}/commit
/v1/numbers-receivables-invoices/{id}/void
Persists 1–500 receivables invoices in a single JSON request. Each item becomes its own transaction header with capture_channel='api_partner'; lines are exploded into three legs (trading, VAT bucket, AR control). The per-item post_status field controls whether the header lands as draft (d) or committed (c). Lifecycle endpoints transition existing headers individually.
Required scope
numbers.receivables-invoices.write
Batch request
Content-Type: application/json
{
"schema_version": "1.0.0",
"items": [
{
"external_identifier": "019f0000-aaaa-7bbb-8ccc-1234567890ab",
"counterparty_identifier": "019f1111-bbbb-7ccc-9ddd-222222222222",
"transaction_date": "2026-05-28",
"due_date": "2026-06-27",
"transaction_currency": "ZAR",
"narration": "Consulting fees - May 2026",
"post_status": "committed",
"lines": [
{ "order": 1, "account_number": "4000", "description": "Consulting fee", "line_amount": "1000.00", "vat201_rate_code": "20180401-1" }
]
}
]
}
Item fields
| Field | Required | Notes |
|---|---|---|
external_identifier | No | Partner UUID v7. Unique per client; re-using returns 409 external-identifier-conflict. |
counterparty_identifier | Yes | Mosaic-issued counterparty UUID. Must have an active trade-receivables control account. |
transaction_date | Yes | YYYY-MM-DD. |
due_date | No | YYYY-MM-DD. |
transaction_currency | Yes | ISO 4217 alpha-3 (uppercase). |
narration | Yes | 1–250 chars. |
purchase_order_number | No | ≤ 50 chars. |
document_number | No | When omitted, server allocates the next INV-NNNNNN. |
post_status | No | draft (default) or committed. |
lines | Yes | 1+ lines; each order, account_number, description, line_amount, vat201_rate_code. account_number is resolved to an active account; unknown numbers fail the item with account-number-unknown. |
Batch response
Returns 200 whenever at least one item was persisted (per-item outcomes in results[]). Returns 422 with the same body shape when every item failed.
{
"schema_version": "1.0.0",
"submitted_count": 1,
"succeeded_count": 1,
"failed_count": 0,
"results": [
{
"index": 0,
"status": "created",
"transaction_header_identifier": "019f1234-5678-7abc-9def-0123456789ab",
"external_identifier": "019f0000-aaaa-7bbb-8ccc-1234567890ab",
"post_status_effective": "committed",
"document_number": "INV-000123",
"_links": { "self": "/v1/numbers-receivables-invoices/019f1234-5678-7abc-9def-0123456789ab" },
"warnings": []
}
]
}
Lifecycle
| Endpoint | Transition | Notes |
|---|---|---|
POST /{id}/commit | d → c | Refused with 409 state-transition-invalid if the current status is not d. |
POST /{id}/void | d|c → v | Refused with 409 vat-return-locked if the transaction date sits on or before any active lock (vat_period_locked_date, numbers_date_locked_final, numbers_date_locked). Refused with 409 asset-register-linked if the invoice has active asset-register cost entries. Soft-locks cannot be bypassed by API partners. |
Lifecycle endpoints take no request body, require an Idempotency-Key, and return 204 No Content on success.
VAT rate identifiers
Identical to Spending Methods. Use the SARS-aligned codes (e.g. 20180401-1 for standard-rated output VAT) on each line.
Idempotency
Same semantics as Spending Methods: a fresh UUID v7 per logical request, replays return the original body plus an Idempotent-Replay: true header.
Errors (per item)
| Problem type | When it occurs |
|---|---|
counterparty-not-found | counterparty_identifier does not belong to the client. |
counterparty-receivables-account-missing | Counterparty has no active trade-receivables control account. |
account-number-unknown | One or more account_number values cannot be resolved. |
vat-rate-unknown | One or more vat201_rate_code values cannot be resolved. |
vat-control-account-missing | No active VAT control account configured for the client. |
external-identifier-conflict | external_identifier is already used for this client. |
double-entry-imbalanced | Server-side double-entry guard failed. |