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

Connect Stripe

Connect Stripe per company (NIF) so its payments auto-generate invoices under the right NIF — for the companies you own and, white-label, for the managed accounts you provision.


Connect Stripe to a company (NIF) and every payment on that account auto-generates an invoice under that exact NIF, registered with AEAT when VeriFactu is enabled for it — no manual step. In the multi-NIF model the connection is per company, never per account: each NIF has its own Stripe account, its own invoices, its own numbering.

Two audiences, one API:

  • Your own companies — connect Stripe to any NIF your account owns.
  • Managed companies — a provisioner (agency, accounting firm or fleet) connects Stripe white-label to a NIF it manages, so the holder authorizes from your portal and never leaves it.

This page covers managing the connection (connect · list · configure · disconnect) and its payment events. What a payment then produces — the Fiscal Mirror, taxes, numbering, VeriFactu submission — lives in the Stripe → invoices section.

Endpoints

Four operations manage a connection, and every one of them hangs off the company, so the NIF is always explicit:

Each reference page carries the scope it requires and its full schemas.

The {company_id} in the path is the only source of context — the account that owns the NIF is derived from it, whether that is your own account or one you provisioned. A NIF you do not reach returns 403, the same answer a non-existent one gets.

{connection_id} is the connection's UUID, as returned by the list endpoint — not a provider slug. A NIF can hold several connections of the same provider, so the slug alone does not name one; a connection of another NIF answers 404, exactly like one that does not exist. The provider slug is still what you send in the body when starting a connection: currently only stripe (Stripe Connect) is operative.

All four work for a NIF you own or manage; acting on a NIF you neither own nor manage returns 403. start exists for the white-label flow — connecting a NIF you manage from your own portal — see Connecting a managed NIF.

Connecting a managed NIF

Provisioners connect Stripe by API, white-label — the holder authorizes from your portal and comes back to it. Two steps:

1. Start the connection. Send the provider slug in the body, and optionally a return_url (absolute https://) to send the holder back to your portal after authorizing:

curl -X POST https://app.beel.es/api/v1/companies/550e8400-e29b-41d4-a716-446655440000/payment-connections/authorizations \
  -H "Authorization: Bearer beel_sk_live_xxx" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "stripe",
    "return_url": "https://your-portal.example.com/connections/stripe/return"
  }'

The connection itself only exists once the holder authorizes, which is why opening the authorization is a sibling sub-resource and not a POST on the collection.

Response — an authorization_url you redirect the holder to:

{ "success": true, "data": { "authorization_url": "https://connect.stripe.com/oauth/authorize?..." } }

2. The holder authorizes. They approve on Stripe; BeeL's callback finalizes the connection and redirects to your return_url with query params appended — on success status=success, provider, company_id, connection_id and account (the provider account id, e.g. acct_…); on error status=error, provider and message (an error code). Omit return_url and the callback lands on BeeL's default integrations screen. A return_url that is not an absolute https:// URL is rejected with 422 VALIDATION_ERROR, and a provider BeeL. does not connect with 422 PROVIDER_NOT_SUPPORTED.

The connection is sealed under the NIF's holder, so auto-invoicing runs under the correct NIF — not under your provisioner account.

start requires that you own the NIF or manage it at OPERATE. A NIF you neither own nor manage — or manage only at VIEW — returns 403 ACTIVE_COMPANY_NOT_ACCESSIBLE and no connection is initiated; its holder must connect it from the BeeL. app.

The NIF must be switched on in the mode of your key (beel_sk_test_* → Test, beel_sk_live_* → Live). Otherwise start returns 400 COMPANY_NOT_ACTIVATED_IN_ENVIRONMENT and no authorization_url: activation is what creates the invoice series and tax configuration, so without it every incoming charge would be skipped instead of invoiced. Test and Live activations are independent — see switching a NIF on.

Checking status

curl https://app.beel.es/api/v1/companies/550e8400-e29b-41d4-a716-446655440000/payment-connections \
  -H "Authorization: Bearer beel_sk_live_xxx"

Each connection comes back with its status and its auto-invoicing settings — its fields are in the reference. For the question you are usually asking ("did this provisioned NIF finish connecting?"), read status: a NIF whose holder opened the authorization but never approved it has no connection at all, not a connection in a pending state. An empty list is the normal answer while you wait.

Configuring the connection

curl -X PATCH https://app.beel.es/api/v1/companies/550e8400-e29b-41d4-a716-446655440000/payment-connections/7c3e1a90-5d2b-4f18-9a64-0b1c2d3e4f50 \
  -H "Authorization: Bearer beel_sk_live_xxx" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "auto_invoice_enabled": true, "event_source": "PAYMENTS", "simplificada_threshold": 400 }'

Update a connection changes the settings that decide what BeeL. does with each incoming charge: auto-invoicing, which family of Stripe events it acts on (event_source), customer creation, email delivery, tax-inclusive pricing, series, the simplified threshold and filters. A field you omit keeps its value — except filter_config, which replaces the whole object when sent. What each setting does is in Connection settings.

Disconnecting

curl -X DELETE https://app.beel.es/api/v1/companies/550e8400-e29b-41d4-a716-446655440000/payment-connections/7c3e1a90-5d2b-4f18-9a64-0b1c2d3e4f50 \
  -H "Authorization: Bearer beel_sk_live_xxx"

The connection moves to DISCONNECTED and auto-invoicing stops: BeeL. no longer processes that account's charges. Already-issued invoices are not affected. The authorization is not withdrawn on Stripe's side — remove BeeL. from the connected account in Stripe if you want that too. A connection id that the NIF does not hold gets 404.

Payment events

A connection records every charge it receives as a payment event, whether or not it produced an invoice. This is the audit trail for a NIF's takings, and the place to recover a charge that failed to invoice.

Seven operations, all hanging off the same /v1/companies/{company_id} prefix so the NIF stays explicit:

What an event tells you

The event object reports three separate things, and telling them apart is what makes the endpoint usable:

  • What the provider said — the charge, its fee, the net, who paid, and the provider's own ids. This is reconciliation material: match it against Stripe's own dashboard, never against the invoice.
  • What BeeL. did with it — whether an invoice came out, and if not, why. A failure is classified as well as described, so you can route on the category instead of parsing a message.
  • What you can do next — needs_action, plus the flags below.

Check retry_available, draft_available and discard_available before calling. They tell you which actions the event supports; calling one it doesn't returns 400.

Recovering a charge that did not invoice

  • retry re-runs the normal processing. Use it when the failure was transient — for example the NIF had no default series at the time and now does.
  • draft creates a draft invoice from the event's data (201), for you to review and issue with POST /v1/companies/{company_id}/invoices/{invoice_id}/issue. Use it when automatic processing cannot succeed but the charge is genuine.
# Find the events still waiting on you.
curl "https://app.beel.es/api/v1/companies/550e8400-e29b-41d4-a716-446655440000/payment-connections/7c3e1a90-5d2b-4f18-9a64-0b1c2d3e4f50/events" \
  -H "Authorization: Bearer beel_sk_live_xxx"

# Draft an invoice from one of them.
curl -X POST "https://app.beel.es/api/v1/companies/550e8400-e29b-41d4-a716-446655440000/payment-connections/7c3e1a90-5d2b-4f18-9a64-0b1c2d3e4f50/events/8ee6b023-c4e5-482e-93ca-dc66da2f9cb5/draft" \
  -H "Authorization: Bearer beel_sk_live_xxx" \
  -H "Idempotency-Key: $(uuidgen)"

Closing an event without an invoice

Not every event that needs action should end in a BeeL. invoice:

  • resolve marks it as handled outside BeeL. — for example, you invoiced that charge with another tool. It leaves the events that need action without generating anything, and it is terminal: a resolved event cannot be retried. Only FAILED, SKIPPED or RECEIVED events qualify.
  • discard takes it out of the default list. It stays in the audit trail, and restore brings it back. An event already linked to an issued invoice, or being processed, cannot be discarded.

Both act on the whole payment, not just the event you name: the sale, its failed attempts and its refunds are resolved or discarded together, and restore undoes exactly the discard that took them out. The response carries the event you named.

The life of a charge

sequenceDiagram
autonumber
participant Payer as Payer
participant Stripe as Stripe
participant BeeL. as BeeL
participant You as Your integration
Payer->>Stripe: pays the connected NIF
Stripe->>BeeL: charge notification
BeeL->>BeeL: records a payment event
alt the NIF can issue
  BeeL->>BeeL: issues the invoice and submits it to AEAT
  BeeL-->>You: webhook invoice.issued
  BeeL-->>You: webhook verifactu.status.updated
else something blocks it
  BeeL->>BeeL: event kept with needs_action true
  You->>BeeL: GET .../events to find it
  You->>BeeL: POST .../events/{event_id}/retry or /draft
  BeeL-->>You: 201 draft invoice to review and issue
end