# Connections

A connection links a company to a service BeeL. works through. How to connect and disconnect one, which providers exist and what each can do.

A **connection** links a company to a service that BeeL. works through on its behalf. Today
the only service is `beel_email`, which captures the replies your customers send to the emails
of your invoices (see [Capture replies by email](/guides/reply-capture-by-email)). More
providers will follow, and they will use the same resource.

Connections belong to a **company** (NIF) and to an **environment**: the one of the key that
creates them. A connection made with a `beel_sk_test_` key does nothing in production, and the
other way round.

<Callout type="info">
  Connecting a payment provider such as Stripe is a different resource. See
  [Connect Stripe](/multi-nif/payment-connections).
</Callout>

## Providers

| provider | What it does | auth_type | capabilities | status on creation |
|---|---|---|---|---|
| `beel_email` | Receives the replies of customers to the emails of your invoices, at an address of BeeL. One live connection per company and environment. | `NONE` | `receive_customer_replies` | `ACTIVE` |

`provider` is the **service** through which a message reaches BeeL. `channel` is the **medium**
the customer wrote in (`EMAIL`, `WHATSAPP`...). They are different fields on purpose:
`beel_email` is an email provider, so its replies have `channel: EMAIL`, and a future `gmail` or
`outlook` provider would bring `channel: EMAIL` too. A reply you register yourself has a `channel`
and no provider (see [Register replies from other channels](/guides/registering-replies)).

There is no endpoint that lists providers. The table above is the catalog, and it is generated
from the API contract. A connection you read may have a `provider`, `auth_type` or `capability`
you do not know yet: ignore it instead of failing.

## Connect a service

`POST /v1/companies/{company_id}/connections` with the `provider` and, optionally, its
`capabilities`. Omit them, or send an empty list, to get the default of the provider. Send an
`Idempotency-Key`, as on every write.

```bash
curl -X POST "https://app.beel.es/api/v1/companies/$COMPANY_ID/connections" \
  -H "Authorization: Bearer $BEEL_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"provider": "beel_email", "capabilities": ["receive_customer_replies"]}'
```

The connection is `ACTIVE` at once and `connection.connected` is delivered to your webhook
endpoints. The response carries the settings of the provider under a property named like it:

```json
{
  "success": true,
  "data": {
    "id": "8c3e1f7a-2b4d-4e6f-9a1c-5d7b3e9f2a41",
    "provider": "beel_email",
    "auth_type": "NONE",
    "capabilities": ["receive_customer_replies"],
    "status": "ACTIVE",
    "created_at": "2026-11-03T08:00:00Z",
    "disconnected_at": null,
    "beel_email": { "reply_domain": "reply.beel.es" }
  }
}
```

Credentials are never part of a connection.

| Status | Answer | Why |
|---|---|---|
| `422` | [`CONNECTION_PROVIDER_NOT_SUPPORTED`](/errors/CONNECTION_PROVIDER_NOT_SUPPORTED) | BeeL. does not connect that `provider`. |
| `422` | [`CONNECTION_CAPABILITY_NOT_SUPPORTED`](/errors/CONNECTION_CAPABILITY_NOT_SUPPORTED) | The provider does not support a capability; `error.details.capability` names it. |
| `422` | [`CONNECTION_REPLY_TO_REQUIRED`](/errors/CONNECTION_REPLY_TO_REQUIRED) | `beel_email` needs the `email` of the company. It is checked before the `409`. |
| `409` | [`CONNECTION_DUPLICATE`](/errors/CONNECTION_DUPLICATE) | The provider allows one live connection per company and environment, and it exists; `error.details.connection_id` is its id. |
| `403` | [`INSUFFICIENT_SCOPE`](/errors/INSUFFICIENT_SCOPE) | The key lacks `connections:write`. See [Permissions](/guides/reply-permissions). |

## Read and disconnect

- [List the connections](/connections/listCompanyConnections) of a company, most recent
  first, with the `provider` and `status` filters. Disconnected ones are included.
- [Get a connection](/connections/getCompanyConnection) by id, also when it is
  `DISCONNECTED`.
- [Disconnect](/connections/disconnectCompanyConnection) with
  `DELETE /v1/companies/{company_id}/connections/{connection_id}`. BeeL. stops doing what the
  `capabilities` allowed, the connection stays readable as `DISCONNECTED` and
  `connection.disconnected` is delivered once. Repeating the call answers `204` and delivers
  nothing.

`DISCONNECTED` is final. To start again, connect again: that creates a new connection with a new id. For `beel_email`, see what is captured in [Capture replies by email](/guides/reply-capture-by-email#what-is-captured-and-what-is-not).

## Webhooks

| Event | When |
|---|---|
| [`connection.connected`](/webhook-events/onConnectionConnected) | A connection is created. |
| [`connection.disconnected`](/webhook-events/onConnectionDisconnected) | A connection becomes `DISCONNECTED`. |

Both carry the connection as it is after the change, only reach the endpoints of the account that
owns the company, and need the `connections:read` scope to subscribe to. The envelope and
signature are the ones of every [webhook](/webhooks/events).

## Related

<Related>

- [Capture replies by email](/guides/reply-capture-by-email): what `beel_email` does to your invoice emails
- [Permissions](/guides/reply-permissions): who can connect and disconnect
- [Connect a service](/connections/createCompanyConnection): the endpoint reference

</Related>

---

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