> ## Documentation Index
> Fetch the complete documentation index at: https://bundleup.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Connection Lifecycle

> How a connection is created, how its tokens are kept fresh, what happens when a refresh fails, and how connections end.

A connection lives from the moment a user authorizes an account until it’s deleted. In between, BundleUp keeps its access token usable so your requests just work.

```mermaid theme={null}
stateDiagram-v2
    state "Background refresh" as BackgroundRefresh
    [*] --> Active: User completes the authorization flow<br/>(connection.created)
    [*] --> Active: Tokens imported with POST /v1/connections<br/>(connection.created)

    Active --> Refreshing: A request arrives and the token<br/>expires within 60 seconds
    Active --> BackgroundRefresh: A request arrives and the token<br/>is due for an early refresh
    Refreshing --> Active: Refresh succeeds<br/>(connection.refreshed)
    BackgroundRefresh --> Active: Refresh succeeds<br/>(connection.refreshed)
    Refreshing --> Active: Refresh fails, this request fails.<br/>The next request tries again
    BackgroundRefresh --> Active: Refresh fails silently.<br/>The current token is still valid

    Active --> Active: External ID changed<br/>(connection.updated)
    Active --> [*]: Deleted<br/>(connection.deleted)
```

A connection starts **Active**. Each request checks the access token. If it’s about to expire, BundleUp refreshes it before forwarding the request. If it’s only due for an early refresh, BundleUp refreshes it in the background. A failed refresh doesn’t disable the connection; the next request tries again. The connection ends when it’s deleted.

## Creation

A connection is created when:

* a user completes the [authorization flow](/docs/guides/auth/authorization-flow), or
* you import existing tokens with `POST /v1/connections` (useful when migrating from your own OAuth implementation).

Either way, you receive a `connection.created` [webhook](/docs/guides/webhooks/events).

## Token refresh

Access tokens expire. Some last an hour, some a few minutes, some never. BundleUp keeps them fresh **on demand**, at the moment a request needs them:

| Token state when a request arrives | What BundleUp does |
| - | - |
| Valid, not yet due for refresh | Uses it. |
| Valid, but past its refresh time | Uses it for this request, and refreshes it **in the background**. The request doesn’t wait. |
| Expired, or expiring within **60 seconds** | Refreshes it **first**, then uses the new token. The request waits for the refresh. |
| No expiry reported by the provider | Uses it. Nothing to refresh. |

If several requests for the same connection need a refresh at the same moment, only one refresh call is made to the provider and all requests use its result. This matters for providers that rotate refresh tokens: two simultaneous refreshes would otherwise invalidate each other.

Each successful refresh sends a `connection.refreshed` webhook.

You can also refresh a connection by hand from the dashboard (**Connections → Refresh connection token**), for example after fixing an integration’s credentials.

<Note>
  Because refresh happens on demand, a connection that isn’t used for a long time isn’t refreshed in the meantime. That’s fine for most providers: the refresh token is still valid when the next request arrives. A few providers expire unused refresh tokens after a period of inactivity, in which case the user needs to reconnect.
</Note>

## When a refresh fails

A refresh can fail because the user revoked access at the provider, the provider expired the refresh token, the integration’s client secret changed, or the provider was briefly unavailable.

* **If the token had already expired**, the request that triggered the refresh fails and nothing is sent to the provider. On the Proxy and MCP, you get `400 connection_refresh_failed` when the connection has no refresh token, or a `5xx` error when the provider rejects the refresh.
* **If the refresh was a background one**, the current token is still valid, so your request goes through. The failure is silent.

In both cases the connection stays as it is. **BundleUp doesn’t limit refresh attempts and doesn’t disable connections automatically.** The next request that needs a fresh token tries again. Temporary provider problems fix themselves.

If refreshes keep failing, the cause is permanent (usually the user revoked access) and the fix is to ask the user to reconnect:

1. Watch for repeated `connection_refresh_failed` errors, or `401`/`403` responses from the provider, on the same connection.
2. Show the user a “Reconnect” prompt that runs the [authorization flow](/docs/guides/auth/authorization-flow) again.
3. Store the new connection ID and delete the old connection.

## Updates

The only field you can change on a connection is its **external ID**, from the dashboard or with `PATCH /v1/connections/{id}`. Changing it sends `connection.updated`.

To change a connection’s scopes, the user has to go through the authorization flow again, which creates a new connection.

## Deletion

Delete a connection when the user disconnects the integration in your product, or when you replace it with a new one:

```bash theme={null}
curl -X DELETE https://api.bundleup.io/v1/connections/conn_abc123 \
  -H "Authorization: Bearer YOUR_API_KEY"
```

BundleUp asks the provider to revoke the token where the provider supports revocation, then deletes the stored credentials. You receive `connection.deleted`. Any later request with that connection ID fails with `connection_invalid`.

Deleting an **integration** deletes all of its connections.

## When users revoke access at the provider

If a user removes your app from their account in the provider’s settings, BundleUp isn’t told. The connection still exists, but the provider rejects its token, usually with `401`. The next refresh also fails. Handle it like any permanent refresh failure: prompt the user to reconnect, then delete the old connection.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.