## Headers base

| Header | Obligatorio | Descripción |
| --- | --- | --- |
| `Authorization: Bearer <beacon_session_token>` | Sí en rutas autenticadas | Token de sesión Beacon resuelto a un usuario local |
| `Content-Type: application/json` | Sí (POST/PATCH) | Formato del payload |
| `Stripe-Signature` | Sí en `/api/webhooks/stripe*` | Firma Stripe validada contra el secreto del entorno |

## Autenticación real

- El bearer token se valida contra la sesión Supabase/Beacon y se resuelve a un usuario local.
- Las rutas documentadas aquí requieren contexto de organización (`org`) y, en la práctica, membresía `OWNER` o `ADMIN`.
- `mode=test|live` se valida contra el hostname de la petición. `test.beacon.pt` rechaza `live` y `app.beacon.pt` rechaza `test`.

## Deduplicación real

- No existe un header público genérico `Idempotency-Key` en las rutas actuales de Beacon.
- `POST /api/billing/subscription/checkout` genera la clave de idempotencia Stripe en servidor y puede reutilizar un checkout pendiente para la misma operación lógica.
- `POST /api/webhooks/stripe` deduplica por `event.id`; los duplicados devuelven `duplicate: true`.
- Las rutas de replay o conciliación devuelven `queueJobId` y pueden reutilizar trabajo ya en curso.

## Errores típicos

| Código | Significado | Acción |
| --- | --- | --- |
| `401` | token inválido o ausente | renovar credenciales y reintentar |
| `403` | el usuario no es elegible | revisar permisos de organización |
| `409` | ya existe un estado pendiente o conflicto de dominio | inspeccionar el estado actual antes de forzar una nueva acción |
| `422` | validación de dominio fallida | corregir el payload funcional y reintentar |

## Ejemplo de petición segura

```bash
curl -X POST "https://test.beacon.pt/api/billing/subscription/checkout?org=acme&mode=test" \
  -H "Authorization: Bearer <beacon_session_token>" \
  -H "Content-Type: application/json" \
  -d '{"plan":"plus","billingCycle":"monthly"}'
```
