# Invoice lifecycle

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

[← All rules](/rules#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](/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.

| Status | Edit ([LIF-001](/rules/lifecycle#lif-001)) | Delete ([LIF-001](/rules/lifecycle#lif-001)) | Issue ([LIF-002](/rules/lifecycle#lif-002)) | Correct ([COR-001](/rules/corrective#cor-001)) |
|---|---|---|---|---|
| `DRAFT` | ✓ | ✓ | ✓ | — [`INVOICE_NOT_CORRECTIBLE_IN_CURRENT_STATUS`](/errors/INVOICE_NOT_CORRECTIBLE_IN_CURRENT_STATUS) |
| `SCHEDULED` | ✓ | ✓ | — [`ONLY_DRAFT_EMITTABLE`](/errors/ONLY_DRAFT_EMITTABLE) | — [`INVOICE_NOT_CORRECTIBLE_IN_CURRENT_STATUS`](/errors/INVOICE_NOT_CORRECTIBLE_IN_CURRENT_STATUS) |
| `ISSUED` | — [`STATUS_NOT_MODIFIABLE`](/errors/STATUS_NOT_MODIFIABLE) | — [`STATUS_NOT_DELETABLE`](/errors/STATUS_NOT_DELETABLE) | — [`ONLY_DRAFT_EMITTABLE`](/errors/ONLY_DRAFT_EMITTABLE) | ✓ |
| `SENT` | — [`STATUS_NOT_MODIFIABLE`](/errors/STATUS_NOT_MODIFIABLE) | — [`STATUS_NOT_DELETABLE`](/errors/STATUS_NOT_DELETABLE) | — [`ONLY_DRAFT_EMITTABLE`](/errors/ONLY_DRAFT_EMITTABLE) | ✓ |
| `PAID` | — [`STATUS_NOT_MODIFIABLE`](/errors/STATUS_NOT_MODIFIABLE) | — [`STATUS_NOT_DELETABLE`](/errors/STATUS_NOT_DELETABLE) | — [`ONLY_DRAFT_EMITTABLE`](/errors/ONLY_DRAFT_EMITTABLE) | ✓ |
| `RECTIFIED` | — [`STATUS_NOT_MODIFIABLE`](/errors/STATUS_NOT_MODIFIABLE) | — [`STATUS_NOT_DELETABLE`](/errors/STATUS_NOT_DELETABLE) | — [`ONLY_DRAFT_EMITTABLE`](/errors/ONLY_DRAFT_EMITTABLE) | ✓ |
| `VOIDED` | — [`STATUS_NOT_MODIFIABLE`](/errors/STATUS_NOT_MODIFIABLE) | — [`STATUS_NOT_DELETABLE`](/errors/STATUS_NOT_DELETABLE) | — [`ONLY_DRAFT_EMITTABLE`](/errors/ONLY_DRAFT_EMITTABLE) | — [`INVOICE_NOT_CORRECTIBLE_IN_CURRENT_STATUS`](/errors/INVOICE_NOT_CORRECTIBLE_IN_CURRENT_STATUS) |

## LIF-001 · An issued invoice is never edited or deleted

`Required` · Law · Impact: critical · Checked by the API: a request that breaks it is rejected with the error codes listed.

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.

**Applies to:** statuses `ISSUED`, `SENT`, `PAID`, `OVERDUE`, `RECTIFIED`, `VOIDED`; operations [`PATCH /v1/companies/{company_id}/invoices/{invoice_id}`](/invoices/patchCompanyInvoice), [`DELETE /v1/companies/{company_id}/invoices/{invoice_id}`](/invoices/deleteCompanyInvoice)

**Error codes:** [`STATUS_NOT_MODIFIABLE`](/errors/STATUS_NOT_MODIFIABLE) (`422` or `400`), [`STATUS_NOT_DELETABLE`](/errors/STATUS_NOT_DELETABLE) (`400`)

**Legal basis:**

- RD 1007/2023 (RRSIF), art. 8.2.a) — [source](https://www.boe.es/buscar/act.php?id=BOE-A-2023-24840#a8)

  > «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.»

**Incorrect:** Patching the amount of an invoice that is already `ISSUED`: the API answers [`STATUS_NOT_MODIFIABLE`](/errors/STATUS_NOT_MODIFIABLE).

```http
PATCH /v1/companies/{company_id}/invoices/{invoice_id}

{ "lines": [{ "description": "Consulting", "quantity": 1, "unit_price": 900, "main_tax": { "type": "IVA", "percentage": 21 } }] }
```

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

```http
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 } }] }
```

**Related:** [LIF-002 · Only a draft can be issued](/rules/lifecycle#lif-002) · [VOI-001 · Void only an invoice that should never have been issued](/rules/void#voi-001) · [COR-001 · Wrong data on an issued invoice is fixed with a corrective](/rules/corrective#cor-001)

**Explained in:** [Invoice lifecycle › What each status allows](/guides/invoice-lifecycle#what-each-status-allows) · [Amounts and rounding › Issued invoices are never recalculated](/guides/amounts-and-rounding#issued-invoices-are-never-recalculated)

## LIF-002 · Only a draft can be issued

`Required` · BeeL. rule · Impact: high · Checked by the API: a request that breaks it is rejected with the error codes listed.

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.

**Applies to:** statuses `DRAFT`, `SCHEDULED`; operations [`POST /v1/companies/{company_id}/invoices/{invoice_id}/issue`](/invoices/issueCompanyInvoice), [`POST /v1/companies/{company_id}/invoices`](/invoices/createCompanyInvoice)

**Error codes:** [`ONLY_DRAFT_EMITTABLE`](/errors/ONLY_DRAFT_EMITTABLE) (`422`)

**Incorrect:** Calling the issue operation on a scheduled invoice to send it out today: it answers [`ONLY_DRAFT_EMITTABLE`](/errors/ONLY_DRAFT_EMITTABLE).

**Correct:** Removing the schedule, which returns the invoice to `DRAFT`, and then issuing it.

**Related:** [LIF-001 · An issued invoice is never edited or deleted](/rules/lifecycle#lif-001) · [NUM-001 · The number is assigned when the invoice is issued](/rules/numbering#num-001) · [DAT-001 · Do not send an issue date](/rules/dates#dat-001)

**Explained in:** [Invoice lifecycle › Issuing](/guides/invoice-lifecycle#issuing)

## LIF-003 · Test in the sandbox, never with real invoices

`Required` · AEAT criterion · Impact: critical · Responsibility: your integration.

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.

**Applies to:** Production API keys (`beel_sk_live_…`).

**Legal basis:**

- AEAT, Aclaraciones a dudas de los desarrolladores (v1.3), 11. Borradores de factura, pre-facturas, facturas proforma, albaranes, facturas de prueba — [source](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/FAQs-Desarrolladores.pdf)

  > «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.»

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

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

**Related:** [VOI-001 · Void only an invoice that should never have been issued](/rules/void#voi-001) · [NUM-002 · An issued number is never reused, even when the invoice is voided](/rules/numbering#num-002)

**Explained in:** [Testing VeriFactu in sandbox](/verifactu/testing-in-sandbox) · [Proformas](/guides/proformas)

## LIF-004 · Retry writes with the same Idempotency-Key

`Recommended` · BeeL. rule · Impact: critical · Responsibility: your integration. The API also answers the error codes listed.

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`](/errors/INVALID_IDEMPOTENCY_KEY).

**Applies to:** operations [`POST /v1/companies/{company_id}/invoices`](/invoices/createCompanyInvoice), [`POST /v1/companies/{company_id}/invoices/{invoice_id}/issue`](/invoices/issueCompanyInvoice), [`POST /v1/companies/{company_id}/invoices/{invoice_id}/corrective`](/invoices/createCompanyCorrectiveInvoice), [`POST /v1/companies/{company_id}/invoices/{invoice_id}/void`](/invoices/voidCompanyInvoice)

**Error codes:** [`IDEMPOTENCY_KEY_MISMATCH`](/errors/IDEMPOTENCY_KEY_MISMATCH) (`409`), [`IDEMPOTENCY_KEY_PROCESSING`](/errors/IDEMPOTENCY_KEY_PROCESSING) (`409`), [`INVALID_IDEMPOTENCY_KEY`](/errors/INVALID_IDEMPOTENCY_KEY) (`400`), [`INVOICE_DUPLICATE_EXTERNAL_REFERENCE`](/errors/INVOICE_DUPLICATE_EXTERNAL_REFERENCE) (`409`)

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

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

```bash
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
```

**Related:** [LIF-001 · An issued invoice is never edited or deleted](/rules/lifecycle#lif-001) · [NUM-002 · An issued number is never reused, even when the invoice is voided](/rules/numbering#num-002)

**Explained in:** [Idempotency](/guides/idempotency)

## LIF-005 · Duplicating an invoice creates a new one, not a copy

`Required` · BeeL. rule · Impact: medium · Responsibility: your integration.

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.

**Applies to:** operations [`POST /v1/companies/{company_id}/invoices/derivations`](/invoices/createCompanyInvoiceDerivation)

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

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

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

**Related:** [CNT-011 · Only one original of each invoice exists](/rules/contents#cnt-011) · [NUM-002 · An issued number is never reused, even when the invoice is voided](/rules/numbering#num-002)

**Explained in:** [Invoice lifecycle › Duplicating an invoice](/guides/invoice-lifecycle#duplicating-an-invoice)

[← All rules](/rules#all-rules)

## Related

<Related>

- [Invoice lifecycle](/guides/invoice-lifecycle) — every invoice status, which operations each one allows, and the difference between the fiscal steps (issue, void, correct) and the commercial ones (sent, paid)
- [Amounts and rounding](/guides/amounts-and-rounding) — how BeeL. turns quantities, prices and rates into bases, taxes and totals: precision, the three ways to price a line, per-group tax rounding, IRPF, and the amounts that are rejected
- [Idempotency](/guides/idempotency) — how to use idempotency keys to prevent duplicate operations in the BeeL. API
- [Proformas](/guides/proformas) — send a customer a formal quote with no fiscal validity, then turn it into a real invoice once they accept — as a draft or issued in the same call

</Related>

---

Full OpenAPI spec: https://docs.beel.es/api/openapi