# 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](/multi-nif/managed-accounts), so the
  holder authorizes from *your* portal and never leaves it.

<Callout type="info">
  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](/stripe) section.
</Callout>

## 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](/payment-connections/listCompanyPaymentConnections) —
  `GET /v1/companies/{company_id}/payment-connections`
- [Start a connection (OAuth)](/payment-connections/initiatePaymentConnection) —
  `POST /v1/companies/{company_id}/payment-connections/authorizations`
- [Update its settings](/payment-connections/updateCompanyPaymentConnection) —
  `PATCH /v1/companies/{company_id}/payment-connections/{connection_id}`
- [Disconnect](/payment-connections/disconnectCompanyPaymentConnection) —
  `DELETE /v1/companies/{company_id}/payment-connections/{connection_id}`

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

<Callout type="info">
  **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](/multi-nif/managed-accounts). A NIF you do not reach returns `403`, the
  same answer a non-existent one gets.
</Callout>

<Callout type="info">
  **`{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.
</Callout>

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](/multi-nif/managed-accounts) from your own portal — see
[Connecting a managed NIF](#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:

```bash
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:

```json
{ "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`](/errors/VALIDATION_ERROR), and a `provider` BeeL. does not connect
with `422` [`PROVIDER_NOT_SUPPORTED`](/errors/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.

<Callout type="warn">
  `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`](/errors/ACTIVE_COMPANY_NOT_ACCESSIBLE) and no connection is initiated;
  its holder must connect it from the BeeL. app.
</Callout>

<Callout type="warn">
  **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`](/errors/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](/multi-nif/companies#switching-a-nif-on-in-test-or-live).
</Callout>

## Checking status

```bash
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](/payment-connections/listCompanyPaymentConnections).
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

```bash
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](/payment-connections/updateCompanyPaymentConnection) 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](/stripe/connection-settings).

## Disconnecting

```bash
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](/payment-events/listCompanyPaymentEvents) —
  `GET .../payment-connections/{connection_id}/events`
- [Read one event](/payment-events/getCompanyPaymentEvent) —
  `GET .../payment-connections/{connection_id}/events/{event_id}`
- [Retry processing an event](/payment-events/retryCompanyPaymentEvent) —
  `POST .../payment-connections/{connection_id}/events/{event_id}/retry`
- [Draft an invoice from an event](/payment-events/generateCompanyPaymentEventDraft) —
  `POST .../payment-connections/{connection_id}/events/{event_id}/draft`
- [Mark an event as resolved](/payment-events/resolveCompanyPaymentEvent) —
  `POST .../payment-connections/{connection_id}/events/{event_id}/resolve`
- [Discard an event](/payment-events/discardCompanyPaymentEvent) —
  `POST .../payment-connections/{connection_id}/events/{event_id}/discard`
- [Restore a discarded event](/payment-events/restoreCompanyPaymentEvent) —
  `POST .../payment-connections/{connection_id}/events/{event_id}/restore`

### What an event tells you

[The event object](/payment-events/getCompanyPaymentEvent) 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.

<Callout type="info">
  **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`.
</Callout>

### 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.

```bash
# 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

```mermaid
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
```

## Related

<Related>

- [What a payment generates](/stripe) — fiscal Mirror, taxes, numbering, supported events and VeriFactu submission
- [Managed accounts](/multi-nif/managed-accounts) — provision and operate NIFs as an agency or fleet — the context for white-label connections
- [Connection settings](/stripe/connection-settings) — per-connection options: series, auto-invoicing, fiscal limits
- [API reference](/payment-connections/initiatePaymentConnection) — full request/response schemas for every connection endpoint

</Related>

---

Full OpenAPI spec: https://docs.beel.es/api/openapi