NewTell a voided invoice from a totally rectified one, without a second call
BeeL
Get StartedMulti-NIFVeriFactuStripeAPI ReferenceChangelog

Managed accounts

The provisioner flow for agencies and fleets — provision accounts, choose your access level, track their lifecycle, and issue invoices on their behalf.


A managed account is a separate account that a provisioner (an agency / gestoría or a fleet operator) creates and operates on behalf of the account holder. You keep a chosen access level over each account and can issue invoices for them without them ever touching the API.

The endpoints on this page use the privileged provisioner scopes — granted by BeeL. only on your provisioner key: accounts:write for provisioning and changing access, accounts:read for tracking your portfolio (list, get, usage). All results are scoped to the caller: you only ever see accounts you provisioned.

Quickstart

From zero to invoicing on a business's behalf. Start in sandbox — the same URL, a beel_sk_test_… key routes there.

Get a provisioning key

Use a key with the accounts:write and accounts:read scopes, in the Sandbox environment — they cover provisioning and changing access (accounts:write) plus listing your portfolio and usage (accounts:read). Both are privileged (provisioned by BeeL, not self-assignable). Add companies:read / customers:write / invoices:write to operate on their behalf.

Provision the business

One POST /v1/accounts with a tax_profile and access_level: "OPERATE" creates the account, its NIF (company), default series and VeriFactu config, and returns the company_id you'll invoice against — plus a one-time claim_token. See Provision an account.

Issue in their name

Create a customer and POST /v1/companies/{company_id}/invoices with the company_id the previous step returned. In sandbox it's numbered and (if enabled) submitted to the AEAT test system under their NIF. See Issue invoices on a managed account's behalf.

Go live

Swap to a beel_sk_live_… key. Production issuing under someone else's NIF needs their signed fiscal representation (the OPERATE requirement in Access levels). Optionally hand them the account with the claim_token so they take ownership while you keep your access.

The full lifecycle

End to end, from an email address to a NIF that invoices.

sequenceDiagram
autonumber
participant You as Provisioner
participant API as BeeL. API
participant Holder as Account holder
You->>API: POST /v1/accounts
API-->>You: 201 account_id + claim_token
You->>API: POST /v1/accounts/{account_id}/companies
API-->>You: 201 company_id
You->>API: POST /v1/companies/{company_id}/activations
You->>API: POST /v1/companies/{company_id}/representation
Holder->>API: signs the fiscal representation
You->>API: GET /v1/companies/{company_id}/issuing-readiness
API-->>You: 200 ready true
You->>API: POST /v1/companies/{company_id}/invoices
Holder->>API: claims the account
You->>API: DELETE /v1/accounts/{account_id}/management
StageEndpointDetail
ProvisionPOST /v1/accountsBelow
Add the NIFPOST /v1/accounts/{account_id}/companiesCompanies
Switch on an environmentPOST /v1/companies/{company_id}/activationsCompanies
Authorise issuing on their behalfPOST /v1/companies/{company_id}/representation, then the holder signsCompanies
Confirm it can issueGET /v1/companies/{company_id}/issuing-readinessOverview
Take paymentsPOST /v1/companies/{company_id}/payment-connections/authorizationsPayment connections
OperatePOST /v1/companies/{company_id}/invoicesBelow
Hand overThe holder claims the accountBelow
End the relationshipDELETE /v1/accounts/{account_id}/managementBelow

Access levels

Your access over a managed account is one of three access_level values — the same three used everywhere access is granted or reported in BeeL:

access_levelWhat the holder can do
NONECover their subscription. No access to their data. This is the default.
VIEWRead their invoices, customers, products, series and fiscal data.
OPERATEEverything in VIEW, plus creating and editing them. Issuing on their behalf additionally requires a signed fiscal representation from the account holder.

Which one do you actually need?

The level is cheap to lower and, after the claim, impossible to raise — so the choice is really "what is the most I will ever need from this account?", asked once, up front.

  • OPERATE is for platforms that invoice instead of the holder: fleets billing on behalf of their riders, agencies issuing for clients who never log in. It is the only level that lets you create invoices, customers and payment connections under their NIF — and the only one that requires a signed fiscal representation before production issuing works. Take it whenever issuing is part of your product, even if you do not issue on day one.
  • VIEW is for platforms that report on an account they set up: dashboards, reconciliation, "your invoices" screens. You see the data and the readiness state but cannot change anything, so an integration bug can never emit a fiscal document in someone else's name.
  • NONE is for a relationship that is over in practice but not on paper — you provisioned the account, you still pay for it, and you no longer want access to its data. If you also want to stop paying, what you want is ending the management, not NONE.

Access level never affects billing. Whoever provisioned an account pays for its subscription regardless of the level they keep over it — including NONE.

Provision an account

POST /v1/accountsaccounts:write. Creates a new account and returns a one-time claim_token — plus a ready-to-use claim_url — to deliver to the holder so they can set their password and take ownership. The response status (PROVISIONED · CLAIMED · ACTIVE) tells you where the account stands right after the call.

It is idempotent by external_ref (your own id for the account): re-sending the same external_ref returns 201 with the same account id (not 409) and re-issues a fresh claim_token while the account is still unclaimed — this is how you resend the claim. For exact response idempotency on network retries (no fresh token, no re-sent email), also send an Idempotency-Key header: a repeat with the same key returns the cached response with Idempotency-Replay: true (cached 24h).

Ready-to-invoice in one call

Include a tax_profile to create the account ready to invoice atomically — its NIF profile, its default invoice series (ordinary F, simplified S, corrective R) and VeriFactu config are set up in the same request, and the response returns the company_id you put in the path of every call that invoices for them.

curl -X POST https://app.beel.es/api/v1/accounts \
  -H "Authorization: Bearer beel_sk_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f8c1e10-3b2a-4c9d-8e7f-1a2b3c4d5e6f" \
  -d '{
    "email": "autonomo@example.com",
    "display_name": "Autónomo Example",
    "external_ref": "your-ref-0042",
    "language": "es",
    "access_level": "OPERATE",
    "tax_profile": {
      "nif": "12345678Z",
      "legal_name": "Autónomo Example",
      "entity_type": "INDIVIDUAL",
      "address": {
        "street": "Calle Mayor",
        "number": "10",
        "postal_code": "28001",
        "city": "Madrid",
        "province": "Madrid"
      }
    }
  }'

The full field list, with types and defaults, is in Provision an account. Three of them decide the shape of the whole relationship and are worth reading here:

  • access_level picks how much you can do afterwards, and it is the one choice you cannot fully undo: once the holder claims the account, only they can raise it. See Access levels.
  • external_ref is your own id for the account, and doubles as the idempotency key described above. Pick something stable in your system — a customer id, not a timestamp.
  • tax_profile is what makes the account able to invoice from the first call. It takes the same fields as creating a NIF, and it is required when access_level is OPERATE — issuing on someone's behalf needs a NIF to issue under, so omitting it is 422. Leave it out only when the holder will register their own NIF on claim.

default_irpf_rate has no default. Omit it and the NIF is created with no withholding at all — BeeL. never assumes a rate nobody declared. You know your account holder's regime: send it only when they do withhold (e.g. "default_irpf_rate": 7 for an autónomo who chose the reduced rate), and 0 only when they declared themselves exempt. Preselecting a number falsifies their fiscal declaration.

Response

{
  "success": true,
  "data": {
    "person_id": "9f8c1e10-3b2a-4c9d-8e7f-1a2b3c4d5e6f",
    "account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "PROVISIONED",
    "claim_token": "claim_one_time_secret",
    "claim_url": "https://app.beel.es/reclamar?token=claim_one_time_secret",
    "company_id": "550e8400-e29b-41d4-a716-446655440000"
  }
}

Every field is described in Provision an account. What the shape does not tell you is how two of them interact:

  • claim_token is shown once and never again, so capture it here. Its claim_url is the same token wrapped in the link for the current environment.
  • A null claim_token is not an error — read status to know why. null with status: CLAIMED or ACTIVE means the holder already took ownership, so what they need is a password reset, not another claim link.
  • company_id is null when you sent no tax_profile. The account exists but has no NIF to invoice under yet; get it back later from GET /v1/accounts/{account_id}/companies.

A 409 is returned when the email already belongs to a BeeL. account this request can neither reuse idempotently (same external_ref) nor reactivate. Branch on error.code:

error.codeWhat it means for you
PROVISIONING_ACCOUNT_CLAIMEDYou did manage this account and ended it, but its holder has already claimed it. It is theirs now — ask them to grant you access; provisioning cannot take it back.
PROVISIONING_EMAIL_ALREADY_REGISTEREDThe 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.

Change your access level

PATCH /v1/accounts/{account_id}/access-levelaccounts:write. Set access_level to NONE, VIEW or OPERATE. Returns 204.

curl -X PATCH https://app.beel.es/api/v1/accounts/3fa85f64-5717-4562-b3fc-2c963f66afa6/access-level \
  -H "Authorization: Bearer beel_sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "access_level": "VIEW" }'

A 403 is returned when the account was not provisioned by you, when it does not exist (existence is not disclosed), or when you try to raise the access level after the holder has claimed the account — once claimed, only the holder can raise it; you may keep or lower it.

End your management of an account

DELETE /v1/accounts/{account_id}/managementaccounts:write. Returns 204. You lose access to the account and its NIFs stop counting towards your billable usage from the next billing cycle. Nothing is deleted or anonymised: the holder keeps the account, its NIFs and its invoices, and becomes responsible for their own subscription.

curl -X DELETE https://app.beel.es/api/v1/accounts/3fa85f64-5717-4562-b3fc-2c963f66afa6/management \
  -H "Authorization: Bearer beel_sk_live_xxx"

Reversible only while the account stays unclaimed. If the holder has not claimed it, provisioning the same email again reactivates that same account — same holder, NIFs and invoices — under the external_ref and access_level of the new request. Once they claim it, provisioning returns 409 PROVISIONING_ACCOUNT_CLAIMED: getting the management back then requires their consent, not just their email address. Only the manager who ended the relationship can reactivate it.

Track the accounts you provisioned

Provisioned accounts move through a lifecycle:

PROVISIONED  →  CLAIMED  →  ACTIVE
(created,        (holder set     (holder registered
 pending)         password)       ≥1 NIF, can operate)

Claiming is done by the holder on BeeL., not by you. You deliver the claim_token; the account holder redeems it on BeeL. — sets a password (if new) and takes ownership, moving the account PROVISIONED → CLAIMED. There is no public claim endpoint for you to call: it's a session action on BeeL.'s side, the same way a member accepts an invitation. You track the result with the lifecycle endpoints below.

What claiming changes for you

Less than integrators expect, and one thing more than they expect:

  • You keep your access. Claiming makes the holder the owner of their account; it does not evict you. Your access_level survives untouched.
  • You keep the bill. Whoever provisioned an account pays for its subscription regardless of who owns it or what access level you keep — including NONE.
  • You can no longer raise your own access. Before the claim you set it freely; after it, only the holder can raise it. You may still keep it or lower it. So if you will ever need OPERATE, ask for it before you hand the token over, not after.
  • Reactivation stops being possible. While the account is unclaimed, ending your management and provisioning the same email again brings the same account back. Once claimed, that same call returns 409 PROVISIONING_ACCOUNT_CLAIMED — getting the relationship back then needs their consent, not just their email address.

List

GET /v1/accountsaccounts:read. Newest first, cursor-paginated. Only the accounts you provisioned. Filter by status, or look one up by your own external_ref (returns 0..1 accounts; an unknown external_ref returns an empty list, never an error).

curl "https://app.beel.es/api/v1/accounts?status=ACTIVE&limit=50" \
  -H "Authorization: Bearer beel_sk_live_xxx"

Filters, page size and the response fields are in List provisioned accounts. Two habits make this endpoint the one you reconcile against:

  • Look accounts up by your own external_ref, not by email. It returns 0..1 accounts, and an external_ref you never used returns an empty list rather than an error — so the same call answers "do I already have this customer?" safely.
  • It is cursor-paginated, not page-numbered: follow data.next_cursor until it comes back null. A portfolio that grows between two calls will not skip or repeat rows the way an offset would.

Get one

GET /v1/accounts/{account_id}accounts:read. Returns the authoritative status and access for one account you provisioned. A 403 is returned when it was not provisioned by you or does not exist.

List its NIFs

GET /v1/accounts/{account_id}/companiescompanies:list (plus an access_level other than NONE over the account). POST /v1/accounts returns company_id once, at creation; this is how you get it back afterwards, and the only way to reach an account provisioned without a tax_profile whose holder registered their NIF later.

Issue invoices on a managed account's behalf

With OPERATE access, issue invoices for the managed company by putting its company_id (from the provision response) in the path. In sandbox you can issue right away; in production, real AEAT submission under the holder's NIF requires their signed VeriFactu representation first (the OPERATE requirement in Access levels):

curl -X POST https://app.beel.es/api/v1/companies/550e8400-e29b-41d4-a716-446655440000/invoices \
  -H "Authorization: Bearer beel_sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "STANDARD",
    "recipient": { "legal_name": "Cliente Final SL", "nif": "B87654321" },
    "lines": [ { "description": "Monthly service fee", "quantity": 1, "unit_price": 100 } ]
  }'

The customer you invoice is created the same way, under the same NIF: POST /v1/companies/{company_id}/customers. See Where each identifier goes for the addressing rules and the Invoices API for the body.

Connect a payment provider (white-label)

With OPERATE access you also connect Stripe to each managed NIF white-label — the holder authorizes from your own portal and charges are auto-invoiced under the correct NIF. The connect · list · disconnect endpoints, scopes and OAuth flow are the same as for a company you own — see Connect Stripe for the full flow, and Stripe for how connected charges become invoices.

Provisioning usage

GET /v1/accounts/{account_id}/usageaccounts:read. Returns your provisioning totals, scoped to the caller.

curl https://app.beel.es/api/v1/accounts/3fa85f64-5717-4562-b3fc-2c963f66afa6/usage \
  -H "Authorization: Bearer beel_sk_live_xxx"

Read nifs as "billable units", not as "real NIFs". The unit that is billed is the provisioned account: every account you provision counts as 1, including the empty and unclaimed ones, so nifs normally equals provisioned_accounts and only diverges when an account holds more than one NIF. An account you provisioned and forgot about is still on the bill until you end your management of it.