NewProvince is only required for addresses in Spain
BeeL
Get startedMulti-NIFVeriFactuRulesStripeAPI referenceChangelog

Invoice lifecycle

What can happen to an invoice before and after it is issued: editing, issuing, duplicating, testing and retrying.


All rules

Issuing is the fiscal line: before it, a draft is yours to change or delete; after it, the invoice and its record are fixed and only a later document can change what they say. These rules say what each side allows.

5 rules: 1 from the law, 1 AEAT criterion, 3 BeeL. rules. How to read a rule.

What each status allows

The fiscal actions on an invoice, by status. Each column comes from the rule that governs it; a refused action leaves the invoice as it was.

StatusEditLIF-001DeleteLIF-001IssueLIF-002CorrectCOR-001
DRAFT✓✓✓✕
SCHEDULED✓✓✕✕
ISSUED✕✕✕✓
SENT✕✕✕✓
PAID✕✕✕✓
RECTIFIED✕✕✕✓
VOIDED✕✕✕✕

Refused withEdit: STATUS_NOT_MODIFIABLE · Delete: STATUS_NOT_DELETABLE · Issue: ONLY_DRAFT_EMITTABLE · Correct: INVOICE_NOT_CORRECTIBLE_IN_CURRENT_STATUS

LIF-001RequiredLawCritical

An issued invoice is never edited or deleted

Once an invoice is issued, neither the invoice nor its billing record is changed or removed. Any correction goes through a later document: a corrective invoice or a void.

Why
The billing record is chained and, under VeriFactu, already with AEAT. An edit would make the invoice say something its record does not, and deleting it would leave a hole in the series.
Responsibility
Checked by the API: a request that breaks it is rejected with the error codes listed.
Applies to
Statuses ISSUEDSENTPAIDOVERDUERECTIFIEDVOIDEDOperations patchCompanyInvoicedeleteCompanyInvoice
Error codes
STATUS_NOT_MODIFIABLE 422 or 400, STATUS_NOT_DELETABLE 400
Legal basisRD 1007/2023 (RRSIF), art. 8.2.a)
«Cualquier necesidad de corrección o anulación de los datos registrados deberá ser realizada mediante al menos un registro de facturación adicional posterior, de forma que se conserven inalterables los datos originalmente registrados.»
RD 1007/2023 (RRSIF), art. 8.2.a) · BOE

Patching the amount of an invoice that is already ISSUED: the API answers STATUS_NOT_MODIFIABLE.

PATCH /v1/companies/{company_id}/invoices/{invoice_id}{ "lines": [{ "description": "Consulting", "quantity": 1, "unit_price": 900, "main_tax": { "type": "IVA", "percentage": 21 } }] }

Issuing a corrective invoice against it, which leaves the original as it was.

POST /v1/companies/{company_id}/invoices/{invoice_id}/corrective{ "rectification_type": "PARTIAL", "rectification_code": "R1", "reason": "Price agreed after delivery was lower", "lines": [{ "description": "Consulting (adjustment)", "quantity": -1, "unit_price": 100, "main_tax": { "type": "IVA", "percentage": 21 } }] }
LIF-002RequiredBeeL. rule

Only a draft can be issued

Issue an invoice from DRAFT, or create and issue it in one call. Issuing assigns the number, sets the issue date to today and freezes every amount; a scheduled invoice is issued on its date, or returned to draft first.

Why
Issuing is the step that creates the fiscal document. Everything the invoice says is fixed at that moment, so it can happen only once and only from a draft.
Responsibility
Checked by the API: a request that breaks it is rejected with the error codes listed.
Applies to
Statuses DRAFTSCHEDULEDOperations issueCompanyInvoicecreateCompanyInvoice
Error codes
ONLY_DRAFT_EMITTABLE 422

Calling the issue operation on a scheduled invoice to send it out today: it answers ONLY_DRAFT_EMITTABLE.

Removing the schedule, which returns the invoice to DRAFT, and then issuing it.

LIF-003RequiredAEAT criterionCritical

Test in the sandbox, never with real invoices

Do not issue test invoices with a production key. An invoice issued in production is a real invoice, sent to AEAT and numbered in your series, even if it was meant as a test; one issued by mistake has to be voided.

Why
AEAT does not accept fictitious invoices from a billing system in production. A test issued there stays in the series and in AEAT's records, and only a void takes it out of the books.
Responsibility
Responsibility: your integration.
Applies to
Production API keys (beel_sk_live_…).
Legal basisAEAT, Aclaraciones a dudas de los desarrolladores (v1.3), 11. Borradores de factura, pre-facturas, facturas proforma, albaranes, facturas de prueba
«las facturas de prueba o facturas de formación, elaboradas con un SIF adaptado, siempre que lleguen a ser facturas propiamente hablando (es decir que se generen de forma real, y que no sean simples borradores o prefacturas no confirmadas), deben ser tratadas como si de facturas reales se tratara a los efectos del RD 1007/23 y resto de normativa de desarrollo.»
AEAT, Aclaraciones a dudas de los desarrolladores (v1.3), 11. Borradores de factura, pre-facturas, facturas proforma, albaranes, facturas de prueba · AEAT

Running an end-to-end test suite against production that issues invoices to a dummy customer.

Running the same suite with a sandbox key (beel_sk_test_…): invoices go to AEAT's test environment and never count.

LIF-004RecommendedBeeL. ruleCritical

Retry writes with the same Idempotency-Key

Send an Idempotency-Key header on every call that creates, issues, corrects or voids an invoice, and repeat the same key when you retry. A retried request returns the stored response of the first one, a 5xx included, for 24 hours; a 4xx answer frees the key, so the corrected request can reuse it.

Why
Without it, a timeout followed by a retry can create or issue a second invoice. An issued duplicate consumes a number and a billing record, and can only be voided. A key longer than 255 characters, or with characters other than letters, digits, - and _, is refused with INVALID_IDEMPOTENCY_KEY.
Responsibility
Responsibility: your integration. The API also answers the error codes listed.

Retrying a timed-out create call without a key, or with a new random key on each attempt.

Deriving the key from your own order id, so every retry of the same order sends the same key.

curl -X POST https://app.beel.es/api/v1/companies/{company_id}/invoices \  -H "Authorization: Bearer $BEEL_API_KEY" \  -H "Idempotency-Key: order-1042-invoice" \  -H "Content-Type: application/json" \  -d @invoice.json

RelatedLIF-001NUM-002

Explained inIdempotency

LIF-005RequiredBeeL. rule

Duplicating an invoice creates a new one, not a copy

Do not use the duplicate operation to replace a lost or damaged invoice. It creates a new draft that, once issued, is a different invoice with its own number and its own billing record; to hand over an invoice again, download the same PDF.

Why
Issuing the copy would invoice the same operation twice, in the series and in AEAT's records.
Responsibility
Responsibility: your integration.
Applies to
Operations createCompanyInvoiceDerivation

The customer lost the invoice, so you duplicate it and issue the copy.

You download the PDF of the original invoice again and send it.

GET /v1/companies/{company_id}/invoices/{invoice_id}/pdf

All rules