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

List the accounts you provisioned

Scopeaccounts:read

Returns the accounts you provisioned, newest first. Each carries its lifecycle status (PROVISIONED → CLAIMED → ACTIVE), the access_level you hold over it and the state of its claim link.

  • status: narrows the list to one lifecycle stage.
  • external_ref: looks an account up by the reference you assigned when provisioning it; returns the 0..1 matching accounts.

Cursor pagination. This collection pages by cursor/next_cursor instead of by page, so it carries no pagination block. That is a documented variant of pagination, not a different envelope: the collection still travels under a named key inside data. Keep asking with the next_cursor of the previous response until it comes back null.


GET
/v1/accounts
AuthorizationBearer <token>

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

Query Parameters

status?string

Keeps only the accounts at this lifecycle stage. Omitted, every stage is listed.

Value in"PROVISIONED" | "CLAIMED" | "ACTIVE"
external_ref?string

Your own id for the account; returns the 0..1 matching accounts.

limit?integer

Maximum number of accounts to return per page (1–200). Defaults to 50.

Default50
Range1 <= value <= 200
cursor?string

Opaque pagination cursor from a previous response's next_cursor.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://app.beel.es/api/v1/accounts"
{
  "success": true,
  "data": {
    "accounts": [
      {
        "account_id": "449e7a5c-69d3-4b8a-aaaf-5c9b713ebc65",
        "external_ref": "string",
        "display_name": "string",
        "access_level": "NONE",
        "status": "PROVISIONED",
        "claim": {
          "status": "NOT_ISSUED",
          "expires_at": "2019-08-24T14:15:22Z"
        },
        "company_id": "b2e6a1c3-1a5e-44ae-a8fd-81f76fd715cf",
        "representation_signed": true,
        "created_at": "2019-08-24T14:15:22Z"
      }
    ],
    "next_cursor": "string"
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00Z",
    "request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
{
  "success": false,
  "error": {
    "code": "BAD_REQUEST",
    "message": "Invalid request"
  },
  "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_INVALID_CURSOR",
    "message": "The pagination cursor is not valid: use the next_cursor from the previous page."
  },
  "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"
  }
}

Import managed accounts from a file POST

Provisions the managed accounts described in an uploaded file, switches each one on in Live, and leaves them ready to invoice. It is the same act as calling `POST /v1/accounts` once per row and then `POST /v1/companies/{company_id}/activations`, with the bookkeeping done for you. ## Idempotency and re-runs - **Not atomic:** each row is processed and reported independently, and a row that fails leaves the rows already provisioned in place. `statistics.accounts_created` is how many accounts this call actually created. - **Declarative and re-runnable:** each pass applies only what is missing — an `external_ref` you already provisioned is reconciled, not duplicated, and so are its series and its customers. That is the recovery path for anything that went wrong: fix the cause and upload the same file again; there is no resume and no partial state to clean up. - **`Idempotency-Key`:** required, but the real guarantee is in the data. Rows are idempotent by `external_ref`, so the same file uploaded twice creates nothing twice even under a different key. - **Dry run:** to see what this would do without writing anything, use `POST /v1/accounts/imports/preview`, a separate operation with no effects at all — the import is never governed by a boolean flag. ## Files and limits - **`accounts_file`:** describes the accounts, one per row. - **`customers_file`:** optional, and holds a list of customers applied to **every** account of the import, new and pre-existing alike, so a new managed account is born knowing all the customers and a new customer reaches all the accounts on the next pass. It is the same CSV that `GET /v1/templates/customer-import` describes, and it is idempotent by tax id. - **`options.apply_customers_to_own_company`:** lands those customers on your own company as well — the one in focus, never one chosen for you. That outcome comes back apart, in `own_company_customers`, and stays out of `statistics.customers_created`. - **Limits:** 5 MB per file, 100 rows in the accounts file and 1,000 in the customers file. A larger population is imported in passes, which costs nothing because the file is declarative. ## Live activation Live activation is part of the act: every row is weighed against the same verdict the account state publishes, and only rows entitled to Live are executed; the rest come back `BLOCKED` with the reason. The import never opens a checkout, so it never charges you by surprise: settle your billing once and re-upload. ## Claim tokens `account.claim_token` and `account.claim_url`: each newly provisioned row carries them in this response and nowhere else, so persist them before discarding it. A lost token is re-issued with `POST /v1/accounts/{account_id}/claim-tokens`. Re-uploading the file never breaks the links you already handed out: a row whose account is still unclaimed and holds a valid claim link comes back with `claim_token` and `claim_url` `null` and `account.claim_link_already_issued: true`. Only an account with no valid link left (expired, or never issued) gets a fresh one.

Retrieve a provisioned account GET

Returns one account you provisioned, with the same shape the list returns: its lifecycle `status`, the `access_level` you hold, the state of its claim link and its `company_id` when the account holds exactly one company.