Issue a claim token
Scopeaccounts:writeIssues a single-use claim_token, and the claim_url built from it, so the account's
holder can set a password and take ownership.
email: send it when the account has no holder yet — the person is created by this call. Omit the body to re-issue the token for the holder the account already has. Anemailthat differs from the existing holder's is rejected rather than replacing them.- Lifetime: tokens last 30 days, and only the last one issued is live. Issuing again invalidates the previous token, so the old link stops working the moment you ask for a new one.
- Not an invitation: this hands the account itself over to its holder. To add a
further person to an account that already has one, invite them with
POST /v1/accounts/{account_id}/invitations. - Entitlement: requires
manage_accounts.
Keys are prefixed beel_sk_, and each one carries the scopes it was created with: a key
short of the scope an operation needs is answered 403. The scope an operation requires
is shown next to its title, and the full catalogue lives in the Scopes reference.
Keys are created from the BeeL dashboard. They are secret credentials: do not share them or commit them to source control.
In: header
Path Parameters
Identifier (UUID) of an account you provisioned. An account you did not provision answers exactly like one that does not exist, so its existence is never disclosed.
uuidHeader Parameters
Idempotency key to prevent duplicates in sensitive operations.
- Any unique client-generated string (e.g. an order id). A UUID also works but is not required
- Allowed characters: letters, digits,
_and-(max 255 chars) - Retrying with the same key replays the first response when it was a success (2xx) or a
server error (5xx): same status and body, plus the header
Idempotency-Replay: true. After a 5xx, check whether the operation took effect before retrying with a new key - A 4xx is not stored: the key is released, so the corrected request can reuse it
- Stored responses expire 24 hours after processing
The key is scoped per user and environment, and bound to the request body, so retrying after a network timeout replays the stored response instead of repeating the operation.
| Status | Code | When |
|---|---|---|
400 | INVALID_IDEMPOTENCY_KEY | The key breaks the format rules above. |
409 | IDEMPOTENCY_KEY_PROCESSING | The first request is still in flight. Wait for the Retry-After seconds (2) and retry with the same key. |
409 | IDEMPOTENCY_KEY_MISMATCH | The key was already used with a different body. Use a new key. |
^[a-zA-Z0-9_-]+$length <= 255The holder's email address, used as their login. Required when the account has no holder (else 422). If the account already has one, it must match theirs — a different address returns 409 CLAIM_TOKEN_HOLDER_MISMATCH rather than silently replacing the holder.
email"es" | "en" | "ca"Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://app.beel.es/api/v1/accounts/497f6eca-6276-4993-bfeb-53cbbbba6f08/claim-tokens" \ -H "Content-Type: application/json" \ -d '{ "email": "maria.lopez@example.com", "language": "es" }'{
"success": true,
"data": {
"person_id": "087e858e-473c-4f50-b5b0-c1df6c021550",
"claim_token": "string",
"claim_url": "http://example.com",
"expires_at": "2019-08-24T14:15:22Z"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication is required to access this resource"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "You do not have permission to access this resource"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "PROVISIONING_ACCOUNT_NOT_ACCESSIBLE",
"message": "That account is not managed by your organisation."
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message"
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
},
"type": "https://docs.beel.es/errors/INVOICE_NO_LINES",
"title": "INVOICE_NO_LINES",
"detail": "The invoice must have at least one line",
"instance": "/v1/invoices/abc-123"
}{
"success": false,
"error": {
"code": "CLAIM_TOKEN_EMAIL_REQUIRED",
"message": "The account has no holder yet: send the email of the person who will claim it."
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please try again in 60 seconds."
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "Internal server error"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "UNSUPPORTED_MEDIA_TYPE",
"message": "Unsupported media type: text/plain. Supported: application/json"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}Provision an account POST
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.
Preview an import of managed accounts POST
Reads the same files as `POST /v1/accounts/imports` and answers the same shape without writing anything: no account is provisioned, no NIF is switched on, no series and no customer are created, and nothing is billed. - **Result shape:** `metadata.is_dry_run` is `true`, every write counter in `statistics` is `0`, and `statistics.importable` is what a real import would create. - **Per row:** it resolves the row's own data — including the repairs a spreadsheet export needs, which `accounts_file` describes — whether the tax id is in the AEAT register, whether the `external_ref` is already an account of yours, and the Live activation verdict that decides whether the import would execute the row at all. - **`statistics.live_activations_pending`:** read it before importing. Every NIF switched on in Live adds an item to your subscription, and this is the only place to see the total before it is charged. - **The customers file** is checked once for the whole import: whether a customer is new to a given account depends on the account, and that only shows up when the import runs.