---
title: "Provision an account"
method: POST
path: "/v1/accounts"
tags: ["Accounts"]
---

# Provision an account

`POST /v1/accounts`

## Request

- Base URL: `https://app.beel.es/api`
- URL: `https://app.beel.es/api/v1/accounts`
- Auth: HTTP bearer

Provisions a new account on BeeL and, when it is born with a holder, returns a single-use
`claim_token` to deliver so they can set a password and take ownership.

- **`email`:** send it to create the account with a holder. Omit it and the account is
  created with no person at all, no `person_id` and no `claim_token`; a holder can be
  added later with `POST /v1/accounts/{account_id}/claim-tokens`.
- **`tax_profile`:** send it and the account comes back ready to invoice, with its NIF,
  default invoice series and VeriFactu configuration set up. Omit it and the account's
  company is created without a NIF until its holder registers one. Either way its
  `company_id` is in the response.
- **`access_level`:** the access you retain over the account. Defaults to `NONE`;
  `OPERATE` requires a `tax_profile`.
- **`external_ref`:** the idempotency key. Resending the same one returns the existing
  account rather than creating a second.
- **Entitlement:** requires `manage_accounts`.

## Reactivation

If you previously ended your management of this account
(`DELETE /v1/accounts/{account_id}/management`) and its holder has not claimed it yet,
provisioning the same email reactivates that account instead of creating a new one. The
same account, holder, NIFs and invoices come back under your management, with the
`external_ref` and `access_level` of this request, and it counts towards your billable
usage again. Once the holder has claimed the account it is theirs, and only they can
grant you access again.

## Headers

- `Idempotency-Key` string

## Request body

- ProvisionAccountRequest: Request to provision a new account. You retain management access at the level in `access_level` (defaults to `NONE`). There are two ways to integrate and both are supported. **With `email`** the account is born with a holder (a person who can log in) and the response carries a `claim_token` / `claim_url` to hand over. **Without `email`** the account and its NIF are created with **no person at all** — for platforms whose self-employed workers will never use BeeL. themselves — and the response carries no token. Inviting someone to claim it is a deferred, optional step: `POST /v1/accounts/{account_id}/claim-tokens`. Nothing is invented: BeeL. never fabricates a placeholder email.
  - `email` string, email: Optional. Email address of the account holder, used as their login. Omit it to create the account **without a person**: no login, no `person_id` and no `claim_token`. You can add the holder later with `POST /v1/accounts/{account_id}/claim-tokens`. Required when `send_email` is `true` (there is nobody to write to otherwise) — else `422`.
  - `display_name` string, required: Human-readable name for the account. Must not be blank.
  - `external_ref` string, required: Your own identifier for this account in your system. Used as an idempotency key: re-provisioning with the same `external_ref` returns the existing account (201, not 409).
  - `language` 'es' | 'en' | 'ca': Supported languages: `es` Spanish, `en` English, `ca` Catalan.
  - `access_level` 'NONE' | 'VIEW' | 'OPERATE': How much access an actor has to an account or a company. The same three values are used everywhere access is granted or reported — whether the actor is a member of the account or a provisioner managing it on someone's behalf. `NONE` — no access to the data. `VIEW` — read invoices, customers, products, series and fiscal data. `OPERATE` — everything in `VIEW`, plus creating and editing them. Issuing invoices for an account you manage additionally requires a signed fiscal representation from the account holder (see `/v1/accounts/{account_id}/companies/{company_id}/representation`). Access level never affects billing: whoever provisioned an account pays for its subscription regardless of the level they keep over it.
  - `tax_profile` ProvisionTaxProfile: The account's fiscal identity, to set it up ready to invoice. Same field vocabulary as `POST /v1/accounts/{account_id}/companies` (`CreateCompanyRequest`). Tax rates fall back to system defaults when omitted; the invoice series is always created with system defaults (the holder edits it later).
    - `nif` string, required: Spanish tax id (NIF/CIF). Validated against the AEAT census; an invalid NIF returns 422.
    - `legal_name` string, required: Registered fiscal name.
    - `entity_type` 'INDIVIDUAL' | 'LEGAL_ENTITY', required: Taxpayer type. INDIVIDUAL: Natural person (individual self-employed). LEGAL_ENTITY: Legal entity (company with legal form: SL, SA, etc.).
    - `address` Address, required: Address you send when you create or update a company, a customer or an onboarding. A required field made only of whitespace passes the length checks below but leaves the address without that part, so it is rejected with `422`: `STREET_EMPTY`, `POSTAL_CODE_EMPTY`, `CITY_EMPTY` or `PROVINCE_EMPTY`. Addresses you read back are described by their own schema.
      - `street` string, required: Full address (street, number, floor, etc.) - Latin characters only
      - `number` string: Street number. Optional: omit it when the address has none, or when `street` already carries the address in full.
      - `floor` string: Floor or level
      - `door` string: Door or apartment
      - `postal_code` string, required: Postal code (5 digits for Spain, free format for other countries)
      - `city` string, required: City or town - Latin characters only
      - `province` string: Province or state - Latin characters only. Required for an address in Spain (`country_code` `ES`, or no country at all); optional elsewhere, where many addresses have none. A Spanish address without it is rejected with a `422`.
      - `country` string: Country of the address, as its ISO 3166-1 alpha-2 code (`GB`) or its official name in Spanish, English or Catalan (`Reino Unido`, `United Kingdom`, `Regne Unit`; case and accents are ignored). Anything else, such as `UK`, is rejected with `422 COUNTRY_CODE_REQUIRED`: send `country_code` instead. If it names a different country than `country_code`, `422 COUNTRY_CODE_MISMATCH` (`España` alone yields to a foreign `country_code`: it was the old default). What is stored and returned is always the Spanish name derived from the resulting code, never the text sent. With neither field present, the address is Spanish (`España`).
      - `country_code` string: ISO 3166-1 alpha-2 country code: the canonical field that decides the country of the address. It must be a real country code (`GB`, not `UK`); otherwise `422 COUNTRY_CODE_REQUIRED`. When it is omitted, the code comes from `country` (see there). With neither field present, the address is stored as `ES`.
    - `legal_form` string: Legal form (e.g. `SL`). Recommended for `LEGAL_ENTITY`.
    - `legal_representative` LegalRepresentative: Legal representative data for a legal entity. Only used when entity_type = LEGAL_ENTITY.
      - `full_name` string, required: Full name of the legal representative
      - `nif` string, required: Tax ID of the legal representative (DNI/CIF/NIE)
      - `address` object, required: Address of the legal representative
        - `street` string, required: Full address (street, number, floor, etc.) - Latin characters only
        - `number` string: Street number. Optional: omit it when the address has none, or when `street` already carries the address in full.
        - `floor` string: Floor or level
        - `door` string: Door or apartment
        - `postal_code` string, required: Postal code (5 digits for Spain, free format for other countries)
        - `city` string, required: City or town - Latin characters only
        - `province` string: Province or state - Latin characters only. Required for an address in Spain (`country_code` `ES`, or no country at all); optional elsewhere, where many addresses have none. A Spanish address without it is rejected with a `422`.
        - `country` string: Country of the address, as its ISO 3166-1 alpha-2 code (`GB`) or its official name in Spanish, English or Catalan (`Reino Unido`, `United Kingdom`, `Regne Unit`; case and accents are ignored). Anything else, such as `UK`, is rejected with `422 COUNTRY_CODE_REQUIRED`: send `country_code` instead. If it names a different country than `country_code`, `422 COUNTRY_CODE_MISMATCH` (`España` alone yields to a foreign `country_code`: it was the old default). What is stored and returned is always the Spanish name derived from the resulting code, never the text sent. With neither field present, the address is Spanish (`España`).
        - `country_code` string: ISO 3166-1 alpha-2 country code: the canonical field that decides the country of the address. It must be a real country code (`GB`, not `UK`); otherwise `422 COUNTRY_CODE_REQUIRED`. When it is omitted, the code comes from `country` (see there). With neither field present, the address is stored as `ES`.
    - `trade_name` string: Commercial/trade name shown on invoices (defaults to `legal_name`).
    - `default_main_tax` TaxInfo: Complete tax information with cross-validations: - IVA: real rates 4, 10, 21, and the temporary 2, 5 and 7.5 (see below for 0) - IGIC: 0, 3, 5, 7, 9.5, 15, 20 — here 0 is the real "Tipo Cero" - IPSI: real rates 0.5, 1, 2, 4, 8, 10 (see below for 0) - OTHER: any percentage between 0 and 100 **0 % under IVA and IPSI is not a rate, it is the exemption sentinel.** It is accepted on a line, but only together with an `exemption_reason` (exempt or non-subject operation); on its own it says nothing and the line is rejected. That is why `GET /v1/tax-types` publishes the IVA rates without 0: the legitimate way to a 0 % IVA line is through an exemption reason, which the same response also publishes. IGIC is different — its 0 % is a real legal rate (basic necessities) and needs no reason. **IVA 5 %** (the temporary rate applied from 2022 to electricity, gas and certain foodstuffs) is no longer in force for new operations. AEAT only accepts it on operations dated from 2022-07-01 to 2024-09-30: send the `operation_date` of that period, because without one the issue date decides and a line at 5 % is rejected with `422 VAT_RATE_NOT_ACCEPTED_ON_DATE`. Its equivalence surcharge pair is 0.5 up to 2022-12-31 and 0.62 from 2023-01-01. **IVA 2 % and 7.5 %** (temporary rates of the last quarter of 2024) are accepted only on operations dated from 2024-10-01 to 2024-12-31, with surcharges 0.26 and 1. Exception: when regime_key = "17" (OSS/IOSS) the invoice applies the destination country VAT instead of the Spanish one, so any percentage in the EU range [0, 27] is accepted regardless of the tax type set — including 0 without an exemption reason.
      - `type` 'IVA' | 'IGIC' | 'IPSI' | 'OTHER', required: Tax type by territory: - IVA: Iberian Peninsula and Balearic Islands (4%, 10%, 21%; 2%, 5% and 7.5% only on operations of their period) - IGIC: Canary Islands (0%, 3%, 5%, 7%, 9.5%, 15%, 20%) - IPSI: Ceuta and Melilla (0.5%, 1%, 2%, 4%, 8%, 10%) - OTHER: Configurable 0%-100% Under IVA and IPSI, 0% is not one of these rates: it is the exemption/non-subject sentinel and always travels with an `exemption_reason`. IGIC's 0% is a real rate. See `TaxInfo` for the full rules.
      - `percentage` number, required: Tax percentage
      - `regime_key` '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '10' | '11' | '14' | '15' | '17' | '18' | '19' | '20': Regime key according to VeriFactu regulations. Omitted, `01` (general regime) applies: - 01: General regime operation - 02: Export (IVA and IGIC; not IPSI, whose AEAT list is `01, 08, 11, 18, 19, 20`) - 03: Used goods, art, antiques (not accepted, see below) - 04: Investment gold - 05: Travel agencies - 06: Group of entities (not accepted, see below) - 07: Cash basis - 08: Operation subject to another indirect tax — IPSI or IGIC on an IVA line, IPSI or IVA on an IGIC line. It is **not** the general regime of IGIC, which is `01`. - 09: Mediating agencies - 10: Third-party collections - 11: Local rental - 14: VAT pending in certifications (not accepted, see below) - 15: VAT pending successive tract - 17: OSS and IOSS - 18: Equivalence surcharge - 19: REAGYP - 20: Simplified regime **What AEAT requires with each key** (Validaciones VERI*FACTU 3.1.3.15.6), checked on IVA and IGIC lines before the invoice is numbered. Otherwise the request is rejected with `422` and the code in brackets: - `04`: only reverse charge (an `ISP_ART_84_2_*` reason) or an exemption (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`). - `08`: only `exemption_reason: NO_SUJETA_LOCALIZACION`, at 0 % (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`). - `10`: only `exemption_reason: NO_SUJETA_ART_7_9`, on a `STANDARD` invoice whose recipient has a `nif` (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`, `REGIME_KEY_REQUIRES_STANDARD_INVOICE`, `REGIME_KEY_REQUIRES_RECIPIENT_NIF`). - `11` (IVA): a subject line only at 21 %, and no reverse charge (`REGIME_KEY_REQUIRES_VAT_RATE`, `REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`). - `06` and `14` are not accepted (`REGIME_KEY_NOT_SUPPORTED`): AEAT requires with them data the invoice does not carry (a cost-based taxable base; an operation date after the issue date and a public-administration recipient). - `03` (used goods) is not accepted (`REGIME_KEY_NOT_SUPPORTED`): under it the invoice must not show the tax separately (RD 1619/2012, art. 16.2.c), and it always does. The corrective of an invoice that already carried `03` keeps it. - `05` (travel agencies) and `07` (cash basis) are accepted, and the invoice PDF carries the mention of their regime (RD 1619/2012, art. 6.1 n and p). `07`: no reverse charge, no non-subject reason and, of the exemptions, only art. 20 or `OTRO` (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`). `GET /v1/tax-types` only offers the keys that are accepted. **One exception to "a key you send is the key you get":** when the line ends up carrying an equivalence surcharge — whether you sent `equivalence_surcharge_rate` or it was inherited from the company's tax configuration — a `01` is rewritten to `18`, because a surcharge under the general regime is fiscally incoherent. Send `equivalence_surcharge_rate: 0` explicitly to keep `01`. See `equivalence_surcharge_rate` in the invoice line for the full rules.
    - `default_irpf_rate` number: Default IRPF withholding percentage (use `0` for exempt). Omit it and the company is created with **no withholding at all** — BeeL never assumes a rate nobody declared. You know your account holder's regime; set it explicitly when they do withhold.
  - `send_email` boolean: Optional. When `true`, BeeL emails the account holder a claim link (`/reclamar?token=...`) so they can set their password and take ownership. Defaults to `false`: by default you receive the `claim_token` in the response and deliver it yourself. Requires a deliverable `email`: sending `true` without one returns `422`.

## Response `201`

Account provisioned successfully. **Business idempotency** by `external_ref`: resending the same `external_ref` returns **201 with the same account id** (not 409). While the account is still unclaimed, a claim link that is still valid is **never revoked**: the response comes back with `claim_token` and `claim_url` `null` and `claim_link_already_issued: true`, and no email is re-sent. Only when no valid link remains (expired, or none was ever issued) is a fresh `claim_token` issued. To replace a valid link on purpose, use `POST /v1/accounts/{account_id}/claim-tokens`. For **exact response idempotency** (same body, same token on retries) send an `Idempotency-Key` header — the response is cached for 24h.

- object: The envelope every successful JSON response of the BeeL. API is wrapped in. There are no bare resources in v1 and none are planned: the payload always hangs off `data`. - A **single resource** is an object in `data`. - A **collection** hangs off a named key inside `data`, together with its `pagination`, also inside `data` — `data: {invoices: [...], pagination: {...}}`. - A collection carries `pagination` unless its operation declares itself a **closed catalogue**: a fixed, bounded list with nothing to page through. The declaration is explicit in the operation; a missing `pagination` is never something to infer. - `GET /v1/accounts` pages by cursor (`data: {accounts: [...], next_cursor}`). It is a documented variant of pagination, not another envelope. Putting the array straight into `data` with `pagination` as its sibling is the shape a v2 would adopt; v1 is not being flipped to it.
  - `success` boolean, required
  - `data` object, required: Result of a successful account provision. `claim_token` is a single-use secret to deliver to the account holder so they can set their password and take ownership. It is returned only once; `null` if the account was already claimed, `null` when the account was provisioned without `email` (there is no holder to hand it to yet), and `null` when a repeated provision found a claim link still valid (`claim_link_already_issued: true`). `claim_url` is the ready-to-use claim link BeeL builds for the current environment; `status` disambiguates a `null` `claim_token` (already claimed) from an error.
    - `person_id` string, uuid, nullable: The account holder. `null` when the account was provisioned **without `email`**: it has no person yet, and gains one when a claim token is issued.
    - `account_id` string, uuid, required
    - `status` 'PROVISIONED' | 'CLAIMED' | 'ACTIVE', required: Lifecycle stage of a provisioned account. The claim gates the stage: `PROVISIONED` (created, not yet claimed — the holder has not set a password / taken ownership, even if a NIF was seeded at provisioning or you invoice on their behalf with `OPERATE`); `CLAIMED` (the holder set their password and took ownership, no NIF yet); `ACTIVE` (claimed and has at least one NIF — can operate under their own ownership).
    - `claim_token` string, nullable: Single-use claim token (shown once); `null` if the account is already claimed, or if a claim link issued earlier is still valid (see `claim_link_already_issued`).
    - `claim_url` string, uri, nullable: Ready-to-use claim link for the account holder, built by BeeL for the current environment (no need to assemble `/reclamar?token=` yourself). `null` when `claim_token` is `null`.
    - `claim_link_already_issued` boolean, required: `true` when this call repeated the provision of an unclaimed account that already has a claim link still valid (pending and not expired). That link is **kept working**: nothing is issued or revoked, `claim_token` and `claim_url` come back `null`, and no email is re-sent even with `send_email: true` (there is no token in clear to send). The link you already handed out is the one the holder uses. To replace it on purpose, call `POST /v1/accounts/{account_id}/claim-tokens`, which revokes the previous one. `false` otherwise.
    - `company_id` string, uuid, nullable: The account's company id (a UUID) — send it in the `BeeL-Active-Company` header to operate on this account. Every account is born with one company: with a `tax_profile` it is ready to invoice; without one it has no NIF yet (the holder registers it on claim), and its issuing readiness reports `COMPANY_HAS_NO_NIF` until then. `null` only when resending an `external_ref` whose account now holds two or more companies.
  - `meta` ResponseMeta
    - `timestamp` string, date-time
    - `request_id` string

## Other responses

- `400`: Bad request. From a dashboard session, a `BeeL-Environment` header whose value is not a known environment answers `ENVIRONMENT_HEADER_INVALID`, with the header named in `error.details` (`{"BeeL-Environment": "invalid"}`); it is never read as production. `BUSINESS_RULE_VIOLATION` is the generic answer to an operation the resource does not admit in its current state when that state has no code of its own. It carries no `details`; read the resource again before retrying.
- `401`: Missing or invalid authentication. Like every other error, `message`/`detail` is localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English when the header is missing or asks for none of those.
- `403`: Authenticated but not allowed. Fourteen causes shared by every operation, told apart by `error.code`; an operation that adds a cause of its own names it in its `403`. You can branch on them exhaustively. - `INSUFFICIENT_SCOPE` — the credential lacks a scope the operation requires; `error.details.missing_scopes` names them as a single comma-separated string (for example `"invoices:write,customers:read"`), not as an array; `required_scopes` has the same shape and lists every scope the operation needs. Retrying will not help: mint a key that holds them. - `COMPANY_READ_ONLY` — the scope is there, but your access level over that NIF only lets you read it. - `ACCOUNT_MANAGEMENT_FORBIDDEN` — the scope is there, but your role over the account, or the management relationship you hold over it, does not cover this operation. - `ACCOUNT_NOT_ACCESSIBLE` — the account is not yours to reach, which is also the answer when it does not exist, so existence is never disclosed. - `ACTIVE_COMPANY_NOT_ACCESSIBLE` — the same, for a NIF: the company in the path, or the one named by `BeeL-Active-Company`, is not one this credential may reach — and again, this is also the answer when it does not exist. - `COMPANY_ACCESS_REVOKED` — your access to the NIF was withdrawn while the request was already in flight, so the write was rejected and nothing was recorded. Retrying will not help until the access is granted again. - `LIVE_CREDENTIAL_REQUIRED` — the operation changes the real account and the call came from a test API key (`beel_sk_test_…`). Use your live key or the dashboard. - `FEATURE_NOT_AVAILABLE` — your subscription does not include the entitlement the operation needs; `error.details.feature_code` names it. This gate runs **before** the scope gate, so for such an operation you never see `INSUFFICIENT_SCOPE` first. - `NO_ACTIVE_ACCOUNT` — the credential does not resolve to an account, so no scope can be evaluated against one. Fail-closed, not a permission that can be granted to you. - `OPERATION_REQUIRES_SESSION` — the operation is available only from the web session; no API key and no OAuth2 token can perform it, whatever scopes it holds. - `OPERATION_REQUIRES_API_KEY` — the reverse: the operation needs a scope that only an API key can hold (such as `accounts:write`), so a dashboard session never satisfies it. - `API_KEY_LIVE_NOT_AVAILABLE` — the call came with a live API key (`beel_sk_live_…`) and the account has no Live mode yet. It is never degraded to Test: use your test key, or activate Live first. - `ACCOUNT_REQUIRES_FOCUS_SWITCH` — dashboard session only: you are a member of the account in the path, but it is not the account in focus. Switch focus to it and retry. - `REQUEST_BLOCKED` — the edge security filter stopped the request before the API saw its body, usually because a text field carries something that looks like markup or a script (HTML tags, `<script>`). Review the body and retry.
- `409`: Conflict. Returned when the email is already used by an existing BeeL. account that this request can neither reuse idempotently (same `external_ref`) nor reactivate. Two distinct cases: - `PROVISIONING_ACCOUNT_CLAIMED` — you did manage this account and ended it, but its holder has already claimed it. It is theirs now: ask them to grant you access from their account. Provisioning cannot take it back. - `PROVISIONING_EMAIL_ALREADY_REGISTERED` — the email belongs to an account you never managed, one someone else manages, or one whose management someone else ended. Use a different email or contact support. - `PROVISIONING_EXTERNAL_REF_CONFLICT` — two provisioning requests with the same `external_ref` ran at the same time and the other one created the account first. Retry the same request: it now finds that account and returns it with `201`.
- `422`: Validation error. Specific to this operation: - `PROVISIONING_TAX_PROFILE_REQUIRED` — `access_level` is `OPERATE` and there is no `tax_profile`: invoicing on the account's behalf needs its NIF, so it is refused here rather than at the first invoice. - `PROVISIONING_EMAIL_REQUIRED` — `send_email` is `true` and there is no `email` to send the claim link to. - `DISPLAY_NAME_BLANK` — `display_name` is made only of whitespace: it passes the length check but leaves the account without a name to show. Any other field failure answers `VALIDATION_ERROR`, with the offending field in `error.details`. Other `error.code` values with this status: - `INVALID_IRPF` — the `irpf_rate` is not a withholding rate in force (see `IrpfPercentage`); send one of the published rates. - `INVALID_PERCENTAGE` — the `percentage` is not a rate of that tax type (e.g. IVA 13); the message lists the valid rates. OSS key `17` accepts any EU rate. - `IRPF_RATE_NOT_FOR_CORPORATE_ISSUER` — the issuer is a company (corporate income tax), which can only withhold 0, 19 or 24 %; use one of those. - `IRPF_RATE_ONLY_FOR_CORPORATE_ISSUER` — the rate (e.g. 9.5 % Ceuta/Melilla) only applies to corporate issuers; an individual issuer must use a personal-income-tax rate.
- `429`: Rate limit exceeded. `RATE_LIMIT_EXCEEDED` when the request rate of your credential is over its limit; `TOO_MANY_REQUESTS` when an email the operation sends is held back because too many went out to that recipient in a short time. Either way, retry after the `Retry-After` seconds. `QUOTA_EXCEEDED` is the other `429`: the operation would go over a quota of your plan for the current period (issued invoices, for instance). Retrying does not help until the quota resets or the plan changes. `error.details` carries `feature_code`, `current_usage`, `quota_limit` and `reset_date`, and `RateLimit-Reset` the seconds until the reset when it is known.
- `500`: Internal server error
- `502`: `EXTERNAL_SERVICE_ERROR` — the AEAT census could not be reached to validate the NIF. Only happens when the request carries a `tax_profile`; the account was not created. Nothing was stored. It is transient; repeat the same request later (with the same `Idempotency-Key` if you sent one). No `Retry-After` header is sent.
- `default`: Any status code the operation does not list above. Every operation declares it, so a generated client always has a branch to fall into and never loses the cause of a failure it did not anticipate. This is where the transport-level answers land — `405`, `406`, `415` and `429` — together with any status a future version of the API starts returning. All of them carry the same error envelope as the codes listed explicitly, so `error.code` is what tells them apart: switching on the status code alone is not enough. See «Transport-level errors» in the API description for when each one is produced. A `402` carrying `SUBSCRIPTION_REQUIRED` lands here when the account has no active subscription. `error.details` says why and what to do: `current_status` (absent if it never had one), `required_permission` and `action`. A `503` carrying `SERVICE_UNAVAILABLE` lands here too, with a `Retry-After` header: a dependency of BeeL itself (the database, the email provider) was momentarily unavailable and nothing was done. Retry after those seconds. A `502` carrying `EXTERNAL_SERVICE_ERROR` also lands here: an outbound integration the operation depends on failed or did not answer in time. It is a transient condition — retry with the same `Idempotency-Key` where the operation accepts one. One exception to the envelope: a failure of the network edge that never reaches the application (`502`, `503`, `504`, `524`) is generated by Cloudflare and its body is not BeeL's — it may not even be JSON. Treat those as "no answer", and retry.

---

[API](https://skmtc.dev/beel/apis/beel-public-api.md) · [All operations](https://skmtc.dev/beel/apis/beel-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/beel/apis/beel-public-api/revisions/ffbc0ae31f79?raw)
