Concepts
InvoNexa turns one neutral invoice document into a compliant invoice for the destination country. Four objects do the work.
- Entity: the legal company that issues invoices, with a tax ID and home country.
- Document: the invoice data you send, in JSON.
- Workflow: the ordered steps (validate, sign, report, deliver) applied to a document.
- Receipt: the final status plus an archived copy of what was sent.
Every object has a prefixed id such as ent_, inv_ or wh_, and every response includes a created_at timestamp in ISO 8601 UTC.
Authentication
Send your secret key in the Authorization header. Sandbox keys start with sk_sandbox_; live keys would start with sk_live_. Requests without a valid key return 401.
Authorization: Bearer sk_sandbox_...
Rotate keys from the dashboard at any time. A rotated key keeps working for one hour so you can deploy without downtime.
Invoices
Create an invoice by posting a document. An invoice moves through these statuses:
- queued: accepted and waiting for a worker.
- processing: being validated and signed.
- reported: accepted by the tax authority or network.
- rejected: refused, with a reason you can fix and resend.
{
"id": "inv_k29dm1xq",
"status": "reported",
"country": "ES",
"total": 1210.0,
"currency": "EUR",
"created_at": "2026-03-04T09:12:41.220Z"
}Workflows
A workflow is a named list of steps. Each country ships with a default workflow, and you can clone it to add steps such as an approval hold or a PDF render.
- Triggers: an API call, an uploaded file or a schedule.
- Steps run in order and stop on the first failure.
- Failed runs can be retried from the failed step, not from the start.
{
"name": "es-standard",
"steps": ["validate", "sign", "report:aeat", "deliver:email"]
}Webhooks
We POST a JSON event to your endpoint when something changes. Respond with any 2xx status within 10 seconds. Otherwise we retry with exponential backoff for up to 24 hours.
Each request carries an InvoNexa-Signature header, an HMAC-SHA256 of the raw body using your webhook secret. Always verify it and reject mismatches.
{
"id": "evt_91ac",
"type": "invoice.reported",
"data": { "id": "inv_k29dm1xq", "status": "reported" }
}Errors
We use conventional HTTP codes: 2xx success, 400 malformed request, 401 bad key, 404 not found, 422 validation failed, 429 rate limited and 5xx on our side. Errors share one shape.
{
"error": {
"code": "validation_failed",
"message": "The request body failed validation.",
"fields": { "currency": "Use one of: EUR, USD, GBP." }
}
}Rate limits
Sandbox keys allow 60 requests per minute. When you exceed that you receive 429 with a Retry-After header in seconds. Use exponential backoff with jitter and honour that header.
- Batch work using the bulk endpoint where possible.
- Send an Idempotency-Key header on POSTs so retries never create duplicates.
Sandbox
The sandbox mimics each country without contacting a real authority. Nothing you send is filed, and data is wiped every 30 days. This documentation describes a demo API for illustration only.
To force a rejection, send a customer name ending in "-REJECT". To test slow responses, end it with "-SLOW".