## Before you start

- Beacon's Stripe app must be registered as an **Extension**.
- `STRIPE_EXTENSION_ENABLED=true` in the environment.
- The Stripe account already exists and must be authorized by an `OWNER` or `ADMIN` in Beacon.
- Use the correct runtime: `https://test.beacon.pt` for `mode=test` and `https://app.beacon.pt` for `mode=live`.

<Note title="Hard requirement">Beacon requires `scope=read_only` in the OAuth callback. If Stripe does not return `read_only`, the connection is aborted and the operational error `stripe_oauth_extension_required` is recorded.</Note>

## Recommended flow

<Steps>
  <Step title="1) Start OAuth">In the Beacon Dashboard, open `Integrations` and call `POST /api/stripe/oauth/start?org=<slug>&mode=<mode>`.</Step>
  <Step title="2) Authorize an existing account">Stripe shows OAuth consent for the existing account. Beacon does not create new accounts.</Step>
  <Step title="3) Validate callback">Stripe returns to `GET /api/stripe/oauth/callback?code=...&state=...`. Beacon validates `state`, exchanges the `code` for a token, and confirms the returned scope includes `read_only`.</Step>
  <Step title="4) Confirm ingestion">The connection becomes `ACTIVE` and Beacon starts ingesting only the payments and movements visible in that Stripe account.</Step>
</Steps>

## What this model means

- Beacon does **not** control payments and does **not** create Stripe accounts.
- Beacon only ingests what is **visible** in the connected account.
- If the original charge stays in a third-party platform account, visibility can be partial.
- In those cases, the full fiscal `Sale` only appears when **Beacon Connect** or equivalent data arrives.

## After connecting

1. Confirm the dashboard shows the account as an existing Stripe account connected through OAuth.
2. Verify ingestion of `charge.succeeded`, refunds, disputes and, when applicable, `transfer` / `payout`.
3. Validate that destination-charge cases stay partial until sufficient enrichment arrives.

## Common errors

| Signal | Likely cause | Action |
| --- | --- | --- |
| OAuth blocked at start | `STRIPE_EXTENSION_ENABLED=false` | enable the flag and confirm the Stripe app is registered as an Extension |
| Callback fails with operational error | Stripe did not return `read_only` | fix the Extension setup in Stripe; Beacon does not treat `read_write` as a functional fallback |
| Payment ingested without full `Sale` | partial visibility in the connected account | send Beacon Connect with fiscal buyer, seller and lines |
| `transfer` / `payout` without visible charge | destination charge or platform-controlled flow | treat as partial and enrich through Beacon Connect |

## Beacon Connect in the same flow

- `POST /api/platform-connect/verify-mapping`
- `POST /api/platform-connect/payments`
- `POST /api/platform-connect/refunds`
- `POST /api/platform-connect/disputes`

Each platform uses its own secret and an `externalOrgRef -> organizationId` mapping managed in Beacon's admin console.
