Invoice Lifecycle¶
Invora issues tax invoices, credit notes, and debit notes through one ergonomic surface. You provide the business essentials (buyer, lines, taxes, dates) and the platform computes every total, renders a regulation-compliant document, generates the QR code, and submits to the tax authority when you freeze.
Three services share an identical shape and the same six operations:
| Document | Service | Base path | Use it to |
|---|---|---|---|
| Invoice | SimpleInvoiceService |
/api/v1/simple/invoices |
Bill a customer |
| Credit note | SimpleCreditNoteService |
/api/v1/simple/credit-notes |
Reduce a previously issued invoice (refund, return, post-sale discount) |
| Debit note | SimpleDebitNoteService |
/api/v1/simple/debit-notes |
Increase a previously issued invoice (extra charge, under-billing) |
The examples below use invoices. Credit and debit notes are identical with the path segment swapped.
Two states: Draft and Frozen¶
An invoice carries a single frozen flag:
| State | frozen |
Editable? | Meaning |
|---|---|---|---|
| Draft | false |
Yes | Work in progress. Edit with Update, remove with Delete. |
| Frozen | true |
No | Finalized. The regulation pipeline has run; QR code and signed artifact are available. Immutable. |
There is no separate "validated" step and no deletion after freeze. To adjust a frozen invoice you never edit it: issue a credit note to lower the amount owed or a debit note to raise it.
Operations¶
| RPC | HTTP | Notes |
|---|---|---|
| Create | POST /api/v1/simple/invoices |
Draft by default; set freezeImmediately to finalize in one call |
| Get | GET /api/v1/simple/invoices/{key} |
Full document with computed totals and any authority results |
| Update | PUT /api/v1/simple/invoices/{key} |
Draft only; requires concurrencyStamp |
| Delete | POST /api/v1/simple/invoices/delete |
Draft only; body { "keys": ["..."] } |
| Freeze | POST /api/v1/simple/invoices/{key}/freeze |
Requires concurrencyStamp; submits to the authority |
| List | POST /api/v1/simple/invoices/list |
Filter, sort, cursor pagination; returns summaries |
Money values: DecimalValue¶
Every monetary amount and rate (unitPrice, taxRate, all calculations.*) uses
an exact decimal type so there are no floating-point rounding errors:
{ "units": "100", "nanos": 0 } // 100.00
{ "units": "1000", "nanos": 500000000 } // 1000.50
{ "units": "15", "nanos": 0 } // 15 (e.g. a 15% tax rate)
The value is units + nanos / 1_000_000_000. units is sent as a string (a
64-bit integer in JSON), nanos as a number in the range 0 to 999,999,999 with
the same sign as units.
Create and freeze in one call¶
Set freezeImmediately: true to create and submit in a single round-trip. Send
only quantities, unit prices, and tax rates; the platform computes the rest.
{
"freezeImmediately": true,
"changes": {
"issueAt": "2026-06-11T10:30:00Z",
"supplyDate": { "year": 2026, "month": 6, "day": 11 },
"currencyCode": "SAR",
"buyer": {
"inline": {
"legalName": "Acme Trading Co.",
"vatRegistrationNumber": "310122393500003",
"address": {
"streetName": "King Fahd Road",
"buildingNumber": "1234",
"citySubdivisionName": "Al Olaya",
"cityName": "Riyadh",
"postalZone": "12345",
"countryCode": "SA"
}
}
},
"lines": [
{
"description": "Consulting services",
"quantity": { "value": { "units": "10", "nanos": 0 }, "unitCode": "HUR" },
"unitPrice": { "units": "100", "nanos": 0 },
"tax": { "taxRate": { "units": "15", "nanos": 0 } }
}
]
}
}
The response returns the full SimpleInvoice with a computed calculations block
(here: lineExtensionTotal 1000.00, taxTotal 150.00, payableAmount 1150.00).
Because you froze it, the response also carries the regulation submission outcome
and the QR code.
To create a draft instead, omit freezeImmediately (or set it false), then call
Freeze later.
Buyer: stored party or inline¶
buyer is a choice between a stored party you created earlier and inline details:
Manage stored parties through the Parties service (/api/v2/parties) and reference
them by partyKey.
B2B vs B2C and regulation submission¶
The buyer's VAT status drives how the document is treated. When you freeze, active regulations run automatically:
| Buyer | Document | Saudi Arabia (ZATCA) |
|---|---|---|
Has vatRegistrationNumber |
B2B tax invoice | Cleared before it is valid (blocking) |
| No VAT number | Simplified (B2C) invoice | Reported after issuance (async) |
For simplified (B2C) invoices above the regulatory threshold, Saudi Arabia requires
at least one additionalIds entry on the inline buyer (national ID, commercial
registration, passport, etc.). Other regulations (Egypt ETA, Peppol) follow their
own submission model; see the regulation guides.
After freezing, the response includes the QR code, the signed artifact reference, and the authority status.
Edit a draft¶
{
"concurrencyStamp": "<from your last Get/Create/Update>",
"changes": { "..." }
}
concurrencyStamp is returned by every read; passing it back lets the platform
reject conflicting concurrent edits. Frozen invoices reject Update.
Credit and debit notes¶
Credit and debit notes use the same content shape and the same six operations at
/api/v1/simple/credit-notes and /api/v1/simple/debit-notes. Use a credit
note to lower the amount owed (refund, return, post-sale discount) and a debit
note to raise it (additional charge, under-billing). Like invoices, they compute
their own totals and submit to the tax authority on freeze.
List with filters¶
{
"filter": {
"textSearch": "Acme",
"part": { "onlyFrozen": true }
},
"sort": { "rules": [ { "issueAt": "SORT_DIRECTION_DESCENDING" } ] },
"pagination": { "limit": "20" }
}
List returns lightweight SimpleInvoiceSummary items (no line detail) plus
totalCount and, when more pages remain, nextPageCursor. Pass that token back as
pagination.cursor to fetch the next page; call Get for a full document.
Filter part is a single condition built from one of: key, issueAt, dueDate,
branchId, buyerPartyKey, currencyCode, onlyFrozen, onlyDrafts. Combine
several with the nested and, or, and not parts. Sort rules accept createdAt,
issueAt, dueDate, or payableAmount, each with SORT_DIRECTION_ASCENDING or
SORT_DIRECTION_DESCENDING.
Supporting invoicing APIs¶
You will use these tenant services alongside invoices:
| Service | Base path | Purpose |
|---|---|---|
| Parties | /api/v2/parties |
Stored customers/suppliers referenced by buyer.partyKey |
| Branches | /api/v2/branches |
Multi-branch issuing with distinct tax registrations (branchId) |
| Settings | /api/v2/settings |
Tenant invoicing configuration |
| Code lists / items | /api/v2/code-lists, /api/v2/code-items |
Lookup values (tax categories, unit codes, etc.) |
| Exchange rates | /api/v2/exchange-rates |
FX rates for multi-currency tax reporting |
| Tax reports | /api/v2/tax-reports |
Periodic tax filings |
/api/v2/pdf |
Branded PDF rendering | |
| Regulations | /api/v2/regulations, /api/v1/regulations/zatca |
Enrollment, status, and ZATCA onboarding |