# Changelog

Every change to the BeeL. API, newest first — what moved, when the old way stops working, and how to tell whether it affects you.

Most changes are one entry here. A few are big enough to need the old-to-new route
table, the retirement calendar and a way to check your own integration against it —
those keep their entry in this list and link to the full note.

Every deprecated route also tells you the same thing in its own responses —
`Deprecation: true`, a `Sunset` date and `Link: <successor>; rel="successor-version"` —
so you never have to trust a page over your own traffic.

## Stripe: a buyer with a NIF always gets a standard invoice, and the simplified threshold is deprecated

Oct 9, 2026 · Improved

Three changes to how a connected Stripe account is invoiced. None of them changes an invoice that already exists, and no request or response changes shape.

- **A buyer with a NIF (or foreign identifier) and a complete address always receives a `STANDARD` invoice**, whatever the amount. Before, a charge below the connection's threshold was issued as `SIMPLIFIED`, which never carries the buyer's NIF. Without that data the charge still gets a `SIMPLIFIED` invoice up to 3 000 €.
- **A charge that cannot be invoiced is saved as a draft** instead of waiting as a skipped event: a charge above 3 000 € whose buyer has no NIF or address, and a charge whose NIF the AEAT definitively rejects. The draft appears in **Needs attention**, and on Live connections BeeL. emails the issuer. Complete the recipient and issue it.
- **`simplificada_threshold` is deprecated.** The API still accepts and returns it, with the same validation, but its value no longer affects the invoice type. You can stop sending it.
- **What to do:** nothing is required. If you relied on the threshold to keep small sales to identified buyers as simplified invoices, those sales are now standard invoices. To avoid drafts, collect tax IDs and the full billing address in Stripe.

- `GET /v1/companies/{company_id}/payment-connections` — `simplificada_threshold` is returned but deprecated and ignored
- `PATCH /v1/companies/{company_id}/payment-connections/{connection_id}` — `simplificada_threshold` is still accepted but deprecated and ignored

- [What invoice gets generated](/stripe/generated-invoices#forward-invoices-standard-vs-simplified)
- [Charges that cannot be invoiced automatically](/stripe/generated-invoices#charges-that-cannot-be-invoiced-automatically)
- [Connection settings](/stripe/connection-settings#simplified-threshold-deprecated)

## Stripe: manual 0 % rates and the buyer's country on paid invoices

Oct 8, 2026 · Improved

Two changes to how a connected Stripe account is invoiced. Neither one changes an invoice that already exists.

- **A manual 0 % tax rate in Stripe no longer leaves the charge without an invoice** when the buyer is in the peninsula or the Balearic Islands. This is the rate some platforms create by default. BeeL. applies the default exemption reason your company declared, or asks you to declare it. Buyers in the Canary Islands, Ceuta or Melilla, buyers from other countries, and payments with no postal code still wait in **Needs attention**.
- **`invoice.paid` now sees the buyer's country.** When neither the Stripe invoice nor its customer carries one, BeeL. takes it from the billing address of the payment that paid the invoice, so both events of the same charge see the same buyer.
- **A buyer outside Spain with an incomplete address** is no longer invoiced as if the sale were Spanish. If the sale cannot go on a simplified invoice, the charge waits with a draft to complete, as it already did for the payment event.
- **What to do:** if you sell exempt with a 0 % rate in Stripe, declare your default exemption reason in BeeL. under Settings > Taxes. If you sell outside Spain, collect the full billing address (street, city, postal code and country) at checkout.

- [Charges at 0 %](/stripe/configuracion-impuestos#charges-at-0)
- [Buyers outside Spain](/stripe/generated-invoices#buyers-outside-spain)
- [Data conversion](/stripe/data-conversion)
- [Connection settings](/stripe/connection-settings#auto-invoicing)

## [A unit price with more than 4 decimals is rejected, not rounded](/changelog/unit-price-more-than-4-decimals-rejected)

Oct 2, 2026 · Breaking

A `unit_price` with more than 4 significant decimals now answers `422 LINE_UNIT_PRICE_TOO_MANY_DECIMALS` instead of being rounded silently. Round to 4 decimals, or send the line total.

[Read the migration note](/changelog/unit-price-more-than-4-decimals-rejected)

## [More than one NIF on the API plan: a 403 that routes to sales](/changelog/api-plan-more-than-one-nif-contact-sales)

Sep 30, 2026 · Breaking

On the API plan with no agreed price, a second NIF, or going Live with several, answers `403 CONTACT_SALES_REQUIRED` with a link to sales.

[Read the migration note](/changelog/api-plan-more-than-one-nif-contact-sales)

## [Province is only required for addresses in Spain](/changelog/province-optional-outside-spain)

Sep 28, 2026 · Breaking

`province` is no longer required on an `Address` outside Spain: a foreign customer or inline recipient without one is accepted. A Spanish address without it still answers `422 PROVINCE_EMPTY`.

[Read the migration note](/changelog/province-optional-outside-spain)

## [Simplified invoice exchanges are recorded with VeriFactu](/changelog/simplified-exchange-recorded-with-verifactu)

Sep 28, 2026 · Breaking

With VeriFactu, exchanging simplified invoices now issues the full invoice and records it as `F3`. `SIMPLIFIED_EXCHANGE_NOT_RECORDABLE` now only means a simplified invoice issued without VeriFactu.

[Read the migration note](/changelog/simplified-exchange-recorded-with-verifactu)

## [The VeriFactu status webhook says whether it reports the registration or the cancellation](/changelog/verifactu-status-webhook-operation)

Sep 28, 2026 · New

`verifactu.status.updated` now carries `operation`: `REGISTRATION` or `VOID`. AEAT's answer to a cancellation reaches you by webhook without a lookup.

[Read the migration note](/changelog/verifactu-status-webhook-operation)

## [Corrective invoices and voids follow the rules of the law](/changelog/correctives-and-voids-follow-the-law)

Sep 27, 2026 · Breaking

A corrective can no longer rectify more than was invoiced, has a deadline, and can fix the recipient's data; a sent or paid invoice is voided only if issued in error.

[Read the migration note](/changelog/correctives-and-voids-follow-the-law)

## [Series by type, and what AEAT would reject is refused before numbering](/changelog/invoice-checks-before-numbering)

Sep 27, 2026 · Breaking

A series numbers only its own type, and an invoice AEAT would reject answers `422` before a number is used. Zero-total invoices are accepted and issued paid.

[Read the migration note](/changelog/invoice-checks-before-numbering)

## Exchange simplified invoices for a full invoice

Sep 27, 2026 · New

When a customer who paid with a simplified invoice asks for an invoice with their details, `POST /v1/companies/{company_id}/invoices/simplified-exchanges` issues a `STANDARD` invoice with the lines of up to 50 simplified invoices and the `recipient` you send. It is not a corrective invoice: it documents the same operations again, identifying the customer.

The new invoice lists the ones it replaces in `replaced_invoice_ids`, and each simplified invoice becomes `VOIDED` with the new `void_cause` value `EXCHANGED`, in the same act. The exchange invoice cannot be voided afterwards; if it is wrong, correct it with a corrective invoice.

When the invoice would be recorded with VeriFactu, the request answered `422 SIMPLIFIED_EXCHANGE_NOT_RECORDABLE` and nothing was issued.

**Update:** with VeriFactu the exchange invoice is now issued and recorded as `F3`, and `SIMPLIFIED_EXCHANGE_NOT_RECORDABLE` only names a simplified invoice issued without VeriFactu. An `F3` exchange invoice cannot be corrected yet. See [Simplified invoice exchanges are recorded with VeriFactu](/changelog/simplified-exchange-recorded-with-verifactu).

- **Rejections:** `422 EXCHANGE_REQUIRES_SIMPLIFIED` when an id is not a simplified invoice; `422 SIMPLIFIED_NOT_EXCHANGEABLE` when it is not issued, or was already voided, exchanged or corrected; voiding the exchange invoice answers `422 EXCHANGE_INVOICE_NOT_VOIDABLE`.
- **If you read `void_cause`** with a strict enum, add `EXCHANGED`; `replaced_invoice_ids` is a new optional field on every invoice response.

- `POST /v1/companies/{company_id}/invoices/simplified-exchanges` — New: a full invoice in exchange for simplified invoices

- [Exchange simplified invoices](/invoices/createCompanySimplifiedExchange)
- [Simplified vs standard](/verifactu/simplified-vs-standard)

## [Tax rates are judged by the operation date and the withholding by the issuer](/changelog/tax-rates-by-date-and-issuer)

Sep 27, 2026 · Breaking

Temporary VAT and surcharge rates only on operations of their period, `0.625` becomes `0.62`, companies cannot withhold individuals' IRPF rates, and some regime keys are refused.

[Read the migration note](/changelog/tax-rates-by-date-and-issuer)

## [A new series needs its document type, and what else changes in this release](/changelog/series-type-required-and-behaviour-changes)

Sep 25, 2026 · Breaking

A new series needs `document_type`, several rejections now carry a specific code or status, and an issued invoice's PDF never changes. Plus behaviour changes.

[Read the migration note](/changelog/series-type-required-and-behaviour-changes)

## [CLI 0.3.0: commands follow the routes under the NIF](/changelog/cli-0-3-0)

Sep 24, 2026 · Breaking

CLI 0.3.0 calls only the routes that name the company, so most commands change name: `beel companies list-invoices <company_id>` is now `beel invoices list`.

[Read the migration note](/changelog/cli-0-3-0)

## [Webhook retries now span about 3 days](/changelog/webhook-retries-span-three-days)

Sep 24, 2026 · Improved

A failed webhook delivery is now retried 7 times over about 3 days instead of for about a minute, so a short outage of your endpoint no longer loses events.

[Read the migration note](/changelog/webhook-retries-span-three-days)

## [A recurring template's history lists what did not happen too](/changelog/recurring-history-every-entry)

Sep 22, 2026 · Breaking

The history now includes failed runs, skipped periods and pauses, each with a `type`. For those entries `invoice_id` is `null`.

[Read the migration note](/changelog/recurring-history-every-entry)

## [A simplified invoice can no longer name an identified recipient](/changelog/simplified-invoice-no-identified-recipient)

Sep 22, 2026 · Breaking

Creating or updating a `SIMPLIFIED` invoice whose recipient has a NIF or an alternative identifier now answers `400 SIMPLIFIED_INVOICE_FORBIDS_IDENTIFIED_RECIPIENT`. Issue it as `STANDARD`.

[Read the migration note](/changelog/simplified-invoice-no-identified-recipient)

## [Where the contract and the API disagreed, they now agree](/changelog/contract-and-api-realigned)

Sep 21, 2026 · Fixed

A check of the published contract against the live API found a dozen differences. A few were fixed in the API, and the rest in the contract.

[Read the migration note](/changelog/contract-and-api-realigned)

## [Export lines take regime 02 on their own](/changelog/export-lines-take-regime-02)

Sep 21, 2026 · Fixed

A VAT line exempt under art. 21 or 22 that arrives with `regime_key: "01"` is stored with `"02"`, instead of being refused by AEAT after issue.

[Read the migration note](/changelog/export-lines-take-regime-02)

## Member grants carry the company's name

Sep 21, 2026 · New

Each grant in a member's response and in the grants list now carries `company_name` next to `company_id`, so you can name the company without resolving every id against the account's companies. It is optional and may be `null` for a company that has no name yet. It never falls back to the id.

- `GET /v1/accounts/{account_id}/members/{member_id}/grants` — Each grant carries company_name

- [List a member's grants](/members/listAccountMemberGrants)
- [Retrieve a member](/members/getAccountMember)

## [A phone number in a response no longer promises the input rules](/changelog/phone-in-responses)

Sep 19, 2026 · Improved

The contract stops declaring `minLength` and `pattern` on `phone` in responses; they move to `PhoneInput`. The server sends exactly what it sent before.

[Read the migration note](/changelog/phone-in-responses)

## [The VeriFactu records of an invoice, each with its own status](/changelog/verifactu-records)

Sep 19, 2026 · New

`GET …/invoices/{invoice_id}/verifactu-records` lists the registration and, after a void, the cancellation — each with its own `submission_status`, so you can tell whether AEAT accepted the cancellation.

[Read the migration note](/changelog/verifactu-records)

## [chaining_hash leaves the documentation](/changelog/chaining-hash-leaves-the-contract)

Sep 17, 2026 · Improved

`verifactu.chaining_hash` was declared but never sent, so it is being withdrawn. No response changes: the server behaves exactly as before.

[Read the migration note](/changelog/chaining-hash-leaves-the-contract)

## [A customer used by a live recurring template cannot be deleted](/changelog/customer-delete-blocked-by-recurring)

Sep 17, 2026 · Breaking

Deleting a customer that an active or paused recurring template invoices is now rejected, on the single `DELETE` and row by row in the bulk delete.

[Read the migration note](/changelog/customer-delete-blocked-by-recurring)

## [An OSS line keeps the destination country's VAT](/changelog/oss-keeps-the-destination-vat)

Sep 17, 2026 · Fixed

Our OSS examples set `percentage: 0`, which drops the destination VAT from the breakdown. The API never required it. Check your `regime_key: "17"` lines.

[Read the migration note](/changelog/oss-keeps-the-destination-vat)

## [A recurring template that emails its invoices needs someone to email](/changelog/recurring-auto-send-needs-a-recipient)

Sep 17, 2026 · Breaking

Saving a template with `send_automatically: true` and no recipient now answers `422 SIN_DESTINATARIO_RESOLUBLE`, and malformed recipient addresses are rejected.

[Read the migration note](/changelog/recurring-auto-send-needs-a-recipient)

## [Recurring templates say when they are failing, and which period they last invoiced](/changelog/recurring-is-failing-and-last-slot)

Sep 17, 2026 · New

`is_failing` flags a template from its first failed run, and `last_generated_scheduled_date` gives the latest period it has already invoiced.

[Read the migration note](/changelog/recurring-is-failing-and-last-slot)

## [A recurring template cannot produce an invoice with a negative total](/changelog/recurring-negative-totals-rejected)

Sep 16, 2026 · Breaking

Negative line totals on a template, a generated invoice adding up below zero, and editing a draft to a negative total are now rejected.

[Read the migration note](/changelog/recurring-negative-totals-rejected)

## [Discarding or resolving a payment event acts on the whole charge](/changelog/payment-event-actions-cover-the-whole-charge)

Sep 15, 2026 · Breaking

`discard`, `restore` and `resolve` on a payment event now also apply to the other events of the same charge: its failed attempts, its refunds, its dispute.

[Read the migration note](/changelog/payment-event-actions-cover-the-whole-charge)

## [Recurring templates: quarterly, yearly, and an invoice cap](/changelog/recurring-invoices-cadence-and-cap)

Sep 15, 2026 · New

Templates gain quarterly and yearly cadences, an end after `max_invoices`, a `completion` reason, `draft_in_advance`, and the amount of the next invoice on every row.

[Read the migration note](/changelog/recurring-invoices-cadence-and-cap)

## [Recurring writes reject what they used to swallow](/changelog/recurring-writes-are-strict)

Sep 15, 2026 · Breaking

Payment detail without a method, an inactive series, a window with no occurrence and a blank name are now rejected instead of silently discarded.

[Read the migration note](/changelog/recurring-writes-are-strict)

## [Stripe connections: faster correctives, disputes you can see, and exact amounts](/changelog/stripe-refunds-disputes-and-shipping)

Sep 15, 2026 · Improved

A card refund gets its corrective at once, disputes and voided credit notes raise a review item, and correctives and shipping add up to the cent.

[Read the migration note](/changelog/stripe-refunds-disputes-and-shipping)

## [Resuming a recurring template no longer re-invoices a period](/changelog/resume-keeps-next-generation)

Sep 13, 2026 · Fixed

Resuming keeps `next_generation` when it has not fallen due yet, instead of recalculating from today, which could issue a period twice or undo a skip.

[Read the migration note](/changelog/resume-keeps-next-generation)

## [Payment connections and events: two unused operations retired, and a Sunset for the per-event default](/changelog/payments-cleanup)

Sep 12, 2026 · Breaking

Two never-documented payment-connection operations are gone today; on 11 December 2026 `charges_only` defaults to `true` and three `counts` fields and four schema aliases retire.

- Retired today: `GET …/payment-connections/{connection_id}` (now `405`) and `POST …/payment-connections/{connection_id}/reactivations` (now `404`)
- No operation is deprecated: listing, opening an authorization and reading a single event stay documented and served
- On 11 December 2026 omitting `charges_only` on the event listing reads as `charges_only=true`; until then a request that omits it answers with `Deprecation`, `Sunset` and `Link`
- `counts.ignored`, `counts.needs_action`, `counts.by_failure_reason` and the four `*ManagedPaymentEventResponse` aliases retire the same day

[Read the migration note](/changelog/payments-cleanup)

## [The deprecated flat routes now retire on 9 December](/changelog/flat-routes-retire-9-december)

Sep 10, 2026 · Improved

The retirement date of the deprecated flat routes moves from 10 September to **2026-12-09**. Nothing stopped answering, and you have the whole window again.

[Read the migration note](/changelog/flat-routes-retire-9-december)

## [next_generation is null when there is no next invoice](/changelog/next-generation-null)

Sep 10, 2026 · Breaking

`next_generation` now carries only the date the system will honour, and `null` otherwise: a completed template, or a paused one whose date has passed.

[Read the migration note](/changelog/next-generation-null)

## [Three response fields were never guaranteed](/changelog/contract-drops-guarantees-it-never-had)

Sep 8, 2026 · Improved

`amount`, `currency` and `sending_history.sent_at` leave `required`. No response changes — the contract was promising something the server never did.

[Read the migration note](/changelog/contract-drops-guarantees-it-never-had)

## [A payment connection says which Stripe events it invoices](/changelog/payment-connection-event-source)

Sep 8, 2026 · New

`event_source` (`PAYMENTS`, `INVOICES` or `BOTH`) picks which family of Stripe events a connection invoices. Existing connections are `BOTH`, which is today's behaviour.

[Read the migration note](/changelog/payment-connection-event-source)

## [New webhook event: invoice.pdf.generated](/changelog/webhook-invoice-pdf-generated)

Sep 8, 2026 · New

`invoice.pdf.generated` tells you an invoice's PDF is stored and ready, so you can fetch it instead of polling.

[Read the migration note](/changelog/webhook-invoice-pdf-generated)

## [Clearer rejections, and updates that do not re-ask the census](/changelog/clearer-rejections-and-cheaper-updates)

Sep 6, 2026 · Improved

A customer update only asks the AEAT census when the fiscal pair changes, the invitation `404` stops saying "pending", and readiness names an incomplete identity.

[Read the migration note](/changelog/clearer-rejections-and-cheaper-updates)

## [An import row without an address is a bad row](/changelog/import-rows-without-address)

Sep 6, 2026 · Breaking

A customer import row with an incomplete address is now reported as a bad row instead of being created with placeholder values.

[Read the migration note](/changelog/import-rows-without-address)

## [Payment connections are addressed by id](/changelog/payment-connections-by-id)

Sep 6, 2026 · Breaking

The `{provider}` path segment becomes `{connection_id}` on nine payment-connection paths. The old paths are gone, with no coexistence window.

[Read the migration note](/changelog/payment-connections-by-id)

## [Addresses can be missing, and accept more characters](/changelog/addresses-can-be-missing)

Sep 3, 2026 · Breaking

`issuer.address` is optional and is no longer filled with invented values, and one character set governs every address field.

[Read the migration note](/changelog/addresses-can-be-missing)

## [The API serves its own spec](/changelog/openapi-spec-endpoint)

Sep 3, 2026 · New

`GET /v1/openapi.yaml` and `/v1/openapi.json` serve the public contract — the same document this reference is built from, no API key needed.

[Read the migration note](/changelog/openapi-spec-endpoint)

## [The PDF download waits instead of asking you to poll](/changelog/pdf-download-waits)

Sep 3, 2026 · Improved

`GET .../invoices/{id}/pdf` now waits for the PDF and answers `200`. `Prefer: wait=0` keeps the old pure polling behaviour.

[Read the migration note](/changelog/pdf-download-waits)

## [VeriFactu is a fact of the taxpayer, not a flag per invoice](/changelog/verifactu-is-an-account-fact)

Sep 3, 2026 · Breaking

Whether an invoice reaches the AEAT is now decided by the NIF's regime at issue time. The per-invoice flag and three response fields are gone.

[Read the migration note](/changelog/verifactu-is-an-account-fact)

## [The street number is no longer required in an address](/changelog/street-number-is-optional)

Sep 2, 2026 · Improved

`address.number` is now optional: omit it when the address has none, or when `street` already carries it.

[Read the migration note](/changelog/street-number-is-optional)

## [New webhook event: invoice.schedule_failed](/changelog/webhook-invoice-schedule-failed)

Sep 2, 2026 · New

`invoice.schedule_failed` tells you a scheduled invoice could not be issued, so you find out without opening the dashboard.

[Read the migration note](/changelog/webhook-invoice-schedule-failed)

## [A fully discounted line no longer kills the invoice](/changelog/invoice-zero-amount)

Aug 28, 2026 · Fixed

A line discounted to zero used to reject the whole invoice. Zero is now judged on the invoice total, with `INVOICE_ZERO_AMOUNT`.

[Read the migration note](/changelog/invoice-zero-amount)

## VeriFactu is always on in sandbox

Aug 26, 2026 · Improved

Creating a company in sandbox is asking for a VeriFactu test bench, so the configuration is now born enabled and the NIF is registered with the provider on the first submission — no explicit step. In Live nothing changes: enabling VeriFactu there is still a deliberate act by the taxpayer.

No existing configuration was touched.

- [VeriFactu configuration](/verifactu/getCompanyVeriFactuConfiguration)

## [Four collections paginate, and branding goes wrapped](/changelog/collections-paginate-and-branding-wrapped)

Aug 25, 2026 · Breaking

Four collections now paginate — without `limit` you get the first 20 — and the three branding responses come wrapped in `{success, data, meta}`.

[Read the migration note](/changelog/collections-paginate-and-branding-wrapped)

## [The census is checked before the invoice is numbered](/changelog/census-check-before-numbering)

Aug 23, 2026 · Breaking

Issuing with VeriFactu on checks the recipient against the AEAT census first: an uncensused recipient answers `422`, and no number is spent.

[Read the migration note](/changelog/census-check-before-numbering)

## [OAuth2 leaves the public contract](/changelog/oauth2-out-of-the-contract)

Aug 23, 2026 · Improved

OAuth2 is gone from the spec. Each operation now states the scope it requires in its own description. API key auth is unchanged.

[Read the migration note](/changelog/oauth2-out-of-the-contract)

## [Three filters returned the wrong rows](/changelog/filters-that-were-silently-dropped)

Aug 22, 2026 · Breaking

A literal `%` in a filter value dropped the filter. `series_code` matched any series containing the code. Sorting customers ignored the documented field names. **Only `series_code` changes a response you may rely on today.**

[Read the migration note](/changelog/filters-that-were-silently-dropped)

## [Rate limits now count per IP](/changelog/global-rate-limit)

Aug 22, 2026 · Breaking

The published global ceiling drops to 1000 req/60 s to match what was already enforced. Strict and Global count **per IP**, not per credential.

[Read the migration note](/changelog/global-rate-limit)

## [Request bodies limited to 2 MB](/changelog/request-body-limits)

Aug 22, 2026 · Breaking

Bodies above 2 MB answer `413 REQUEST_BODY_TOO_LARGE`. `411 LENGTH_REQUIRED` is gone — chunked encoding is accepted.

[Read the migration note](/changelog/request-body-limits)

## [Lost updates answer 409](/changelog/concurrent-modification)

Aug 21, 2026 · Improved

Two overlapping updates: the second now answers `409 CONCURRENT_MODIFICATION` instead of silently discarding the first.

[Read the migration note](/changelog/concurrent-modification)

## [Contract drops what was never sent](/changelog/contract-declares-what-the-server-does)

Aug 21, 2026 · Fixed

Several documented responses and one header were never actually sent. They are out of the contract; the server did not change.

[Read the migration note](/changelog/contract-declares-what-the-server-does)

## [Breakdowns, series and schedules](/changelog/invoicing-contract-detail)

Aug 21, 2026 · Improved

Tax breakdowns travel complete and add up. Series publish the next number they will assign. Recurring invoices declare `frequency` in the request.

[Read the migration note](/changelog/invoicing-contract-detail)

## [Import managed accounts from a file](/changelog/managed-account-imports)

Aug 21, 2026 · New

Create managed accounts in bulk from a spreadsheet — template, preview, apply — and see where each claim stands.

[Read the migration note](/changelog/managed-account-imports)

## [Semantic rejections answer 422](/changelog/semantic-rejections-are-422)

Aug 21, 2026 · Improved

A body that parses but breaks a rule now answers `422` with a code and populated `details`, not an empty `400`.

[Read the migration note](/changelog/semantic-rejections-are-422)

## [Unknown query parameters rejected from 3 September](/changelog/strict-query-parameters-and-rate-limits)

Aug 21, 2026 · Breaking

From **2026-09-03** the flat routes reject an undeclared query parameter with `400` instead of ignoring it. Until then they answer `200` with a `BeeL-Warning` header naming it.

[Read the migration note](/changelog/strict-query-parameters-and-rate-limits)

## [Void cause on voided invoices](/changelog/invoice-void-cause)

Aug 21, 2026 · New

Voided invoices now carry `void_cause`, `void_reason` and `voided_at`, so a direct void and a total corrective are told apart without a second call.

[Read the migration note](/changelog/invoice-void-cause)

## [One shape for lists and deletes](/changelog/canonical-surface-consistency)

Aug 17, 2026 · Breaking

Lists answer `data.<plural>`, deletes answer `204` unless the body informs, and every create returns `Location`. `DELETE products/bulk` takes `?ids=` instead of a body.

- Lists: `data` is never a bare array anymore. Six lists that answered `data: [...]` + root `pagination` (companies of an account, series, recurring invoices, payment events, request logs, sent emails) now answer `data.<plural>` + `data.pagination` — deprecated flat aliases included, since they share the schema. Five unpaginated lists (company stats, email indicators, payment connections, recurring history, series defaults) are wrapped in `data.{plural}` with no pagination block.
- Deletes: `DELETE .../customers/{id}` and `DELETE .../representation` now answer `204` with no body — their old `200` bodies carried nothing you could not already know. Bulk deletes and `DELETE .../activations` keep their `200` body (partial results and the computed `effective_at` are only knowable from the response).
- `DELETE /v1/companies/{company_id}/products/bulk` no longer takes a request body — a body on DELETE has no defined semantics and intermediaries may drop it. Send `?ids=` (comma-separated, max 100 per request), same as customers/bulk.
- Every single-resource `201` now carries a `Location` header pointing at the created resource's canonical GET — including actions that produce a resource (corrective, convert, derivations, generate, payment-event draft). Claim tokens point at their `claim_url`. Bulk creations carry none: there is no single URI to point at.
- `PUT /v1/configuration/series/{series_id}` is now deprecated like the rest of the flat series routes. It has no drop-in successor: the canonical `PATCH /v1/companies/{company_id}/series/{series_id}` behaves the same for every body except an explicit `description: null`, which the old `PUT` ignored and the `PATCH` honours by clearing the field.
- Declarative sweep: every live operation now documents `429` and `500`, every tag is declared, and the account companies operations moved from the `PublicCompanies` tag to `AccountCompanies`.
- These changes ship without a grace window: measured traffic on the affected shapes was test-mode only. If your integration reads any of the old list shapes, adapt the paths above — everything else about each operation is unchanged.

[Read the migration note](/changelog/canonical-surface-consistency)

## A webhook URL on a private network is rejected when you register it

Aug 17, 2026 · Improved

Registering or changing a subscription URL that points to a private or internal network address now answers `422 URL_TARGET_NOT_ALLOWED`, instead of creating a subscription that would never receive a delivery. A host that does not resolve yet is still accepted, so you can register before your DNS is live.

- [URL_TARGET_NOT_ALLOWED](/errors/URL_TARGET_NOT_ALLOWED)
- [Create a subscription](/webhooks/createAccountWebhookSubscription)

## [external_reference is now external_ref](/changelog/external-ref-rename)

Aug 13, 2026 · Breaking

The invoice field first announced as `external_reference` is now called `external_ref`. Responses already emit the new name; the old one is still accepted when you write, as a deprecated alias.

- Responses emit `external_ref` — the old name is no longer returned
- Writes still accept `external_reference`, as a deprecated alias
- Affects the request body of the create-invoice routes and the `GET /v1/invoices` query filter
- Nothing has stopped working, and no removal date is announced yet

[Read the migration note](/changelog/external-ref-rename)

## [Webhook subscriptions report their health, and pause when the endpoint is dead](/changelog/webhook-endpoint-health)

Aug 12, 2026 · New

A subscription now says how its endpoint is doing, emails you when it keeps failing, and is paused after 25 failed deliveries over more than 48 hours.

[Read the migration note](/changelog/webhook-endpoint-health)

## [Resources under the NIF](/changelog/resources-under-the-nif)

Aug 7, 2026 · Breaking

New: an account can hold several NIFs, each addressed in the path. As a result the old flat routes are deprecated — 82 operations gain a `Sunset` date, and all but three a successor route, and keep answering until then.

- 82 operations are deprecated, each with a `Sunset` date and, for all but three, a successor route
- Nothing is removed — every deprecated route keeps answering until its `Sunset` date
- Deprecated routes carry `Deprecation: true`, `Sunset` and, where a successor is declared, `Link: <successor>; rel="successor-version"`
- The three replacing `PUT`s (customer, product, recurring invoice) declare no successor: the canonical `PATCH` merges instead of replacing, so it is not a drop-in

[Read the migration note](/changelog/resources-under-the-nif)

## [Filter invoices by several statuses](/changelog/multi-status-invoice-filter)

Aug 3, 2026 · Improved

The `status` filter on `GET /v1/invoices` accepts a comma-separated list, so one request covers several statuses.

[Read the migration note](/changelog/multi-status-invoice-filter)

## [external_reference on invoices](/changelog/invoice-external-reference)

Jul 18, 2026 · New

Invoices accept an `external_reference` — your own order id — that you can filter by and that is enforced as unique.

[Read the migration note](/changelog/invoice-external-reference)

## [Disbursements (suplidos): pass-through payments](/changelog/suplidos)

Jul 15, 2026 · New

Invoice lines carry a `line_type`. Set `SUPLIDO` to pass through amounts paid in your client’s name, outside the taxable base.

[Read the migration note](/changelog/suplidos)

## [Read your API request logs](/changelog/request-logs)

Jun 15, 2026 · New

A Request Logs endpoint family lets you inspect what your own API keys have called — method, path, status, timing and the full detail.

[Read the migration note](/changelog/request-logs)

## [BeeL. CLI](/changelog/cli)

Jun 13, 2026 · New

Official CLI on npm as `@beel_es/cli`. Run any endpoint from the terminal, sandbox by default, nothing to install.

[Read the migration note](/changelog/cli)

## [Node.js / TypeScript SDK](/changelog/node-sdk)

Jun 11, 2026 · New

Official Node.js / TypeScript SDK on npm as `@beel_es/sdk`, fully typed from the spec.

[Read the migration note](/changelog/node-sdk)

## [v1.3.0 — contract fixes](/changelog/v1-3-0)

Jun 10, 2026 · Breaking

Idempotency keys accept any string, `country` becomes optional, and webhook URLs must be HTTPS.

[Read the migration note](/changelog/v1-3-0)

## [Active-company header renamed](/changelog/active-company-header)

Jun 9, 2026 · Improved

The header that selects the active company is now `Beel-Active-Company`, was `X-Active-Profile`.

[Read the migration note](/changelog/active-company-header)

## [v1.2.0 — VeriFactu validation pack](/changelog/v1-2-0)

May 22, 2026 · Breaking

Invalid fiscal combinations now fail at request time with specific `422`s. Adds a public error-code catalog, metadata filters, the RD-ley rates and BIZUM.

[Read the migration note](/changelog/v1-2-0)

## [v1.1.0 — recipient and payment_info](/changelog/v1-1-0)

May 6, 2026 · Breaking

Invoice `recipient` and `payment_info` become structured objects, and new series get sensible defaults.

[Read the migration note](/changelog/v1-1-0)

## [v1.0.3 — exemptions and document types](/changelog/v1-0-3)

Apr 18, 2026 · Breaking

VeriFactu exemptions and document types, plus stricter validation on fiscal fields.

[Read the migration note](/changelog/v1-0-3)

## [v1.0.1 — operation_date](/changelog/v1-0-1)

Mar 26, 2026 · Breaking

`issue_date` is now always today, and a new `operation_date` carries the date the service was actually rendered.

[Read the migration note](/changelog/v1-0-1)

## [BeeL. API v1.0 — public launch](/changelog/api-launch)

Mar 18, 2026 · Release

The BeeL. API is publicly available: invoicing, customers, products, tax configuration and VeriFactu, with a 7-day trial.

[Read the migration note](/changelog/api-launch)

---

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