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:
- List a NIF's connections —
GET /v1/companies/{company_id}/payment-connections - Start a connection (OAuth) —
POST /v1/companies/{company_id}/payment-connections/authorizations - Update its settings —
PATCH /v1/companies/{company_id}/payment-connections/{connection_id} - Disconnect —
DELETE /v1/companies/{company_id}/payment-connections/{connection_id}
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:
- List the events of a connection —
GET .../payment-connections/{connection_id}/events - Read one event —
GET .../payment-connections/{connection_id}/events/{event_id} - Retry processing an event —
POST .../payment-connections/{connection_id}/events/{event_id}/retry - Draft an invoice from an event —
POST .../payment-connections/{connection_id}/events/{event_id}/draft - Mark an event as resolved —
POST .../payment-connections/{connection_id}/events/{event_id}/resolve - Discard an event —
POST .../payment-connections/{connection_id}/events/{event_id}/discard - Restore a discarded event —
POST .../payment-connections/{connection_id}/events/{event_id}/restore
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
retryre-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.draftcreates a draft invoice from the event's data (201), for you to review and issue withPOST /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:
resolvemarks 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. OnlyFAILED,SKIPPEDorRECEIVEDevents qualify.discardtakes it out of the default list. It stays in the audit trail, andrestorebrings 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