export const metadata = {
  title: "Sync, Poll, Webhooks",
  description:
    "Four patterns for interacting with asynchronous FaithTranscripts jobs — sync short pastes, poll long jobs, or receive webhook callbacks.",
  alternates: { canonical: "/docs/api/async" },
};

# Sync, Poll, Webhooks

The pipeline is fundamentally asynchronous: every ingestion enqueues one or
more background jobs. The API supports four interaction patterns on top of
that. All four use the same underlying job — the difference is purely
client-side.

| Pattern         | Good for                        | Ceiling                  |
| --------------- | ------------------------------- | ------------------------ |
| Fire-and-forget | Bulk imports, nightly runs      | None                     |
| Poll            | Simple scripts, no inbound HTTP | Rate limit on reads      |
| Webhook         | Production server-to-server     | Client must expose HTTPS |
| Sync wait       | Pasted text, interactive tools  | 60s (Vercel Hobby)       |

## 1. Fire-and-forget (default async)

<EndpointBadge method="POST" path="/api/v1/transcripts" />

```bash
curl https://www.faithtranscripts.com/api/v1/transcripts \
  -H "Authorization: Bearer ft_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "source_type": "youtube", "url": "https://youtu.be/..." }'
```

Response `202 Accepted`:

```json
{
  "id": "tr_01HW...",
  "status": "pending",
  "ai_pass_status": "idle",
  "jobs": [{ "id": "job_01HW...", "type": "youtube_fetch" }]
}
```

You are responsible for checking back later via polling or a webhook.

## 2. Poll

<EndpointBadge method="GET" path="/api/v1/transcripts/{id}" />
<EndpointBadge method="GET" path="/api/v1/jobs/{id}" />

```bash
curl https://www.faithtranscripts.com/api/v1/transcripts/tr_01HW... \
  -H "Authorization: Bearer ft_live_YOUR_KEY"
```

The read rate limit is generous (600/min per org). Recommended pattern:
**exponential backoff starting at 1s, capping at 30s.** We return a
`Retry-After` header on the first poll as a hint.

<Callout variant="tip">
  The dashboard SSE stream at `/api/sse/[jobId]` is not exposed to API callers
  in v1. Holding long-lived connections from untrusted callers is a DoS surface
  we don't want to operate yet. API callers use polling or webhooks for
  progress.
</Callout>

## 3. Webhooks

Preferred for production integrations. Full details in the [Webhooks guide](/docs/api/webhooks).

Register your HTTPS URL and choose event types from
[Settings → Webhooks](/settings/webhooks). We then POST signed payloads to that
endpoint as transcripts and AI passes reach terminal states (HMAC-SHA256).

## 4. Synchronous wait

For small inputs and interactive callers. Add `?wait=true` to the create
request and the server will block on the job's pub/sub channel until it
reaches a terminal state.

```bash
curl "https://www.faithtranscripts.com/api/v1/transcripts?wait=true&timeout=60" \
  -H "Authorization: Bearer ft_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "source_type": "paste", "content": "..." }'
```

| Query     | Default | Range          | Notes                                   |
| --------- | ------- | -------------- | --------------------------------------- |
| `wait`    | `false` | `true`/`false` | Set to `true` to enable sync mode.      |
| `timeout` | `60`    | `5`–`60` sec   | Upper bound is the Vercel function cap. |

Semantics:

- Response body is the full completed `transcript` object.
- If the job hasn't finished within `timeout`, we return `504 timeout` **but the job keeps running**. The response body still includes the `transcript.id` so you can switch to polling or webhooks.
- Sync requests count against a 10-concurrent-per-org bucket to protect the server from long-held connections. Exceeding it returns `429 rate_limited`.

<Callout variant="warn">
  **When not to use sync:** YouTube fetches (captions may take several seconds
  to resolve), AI pass on long transcripts (chunked, can exceed the 60s
  ceiling), or any client on a flaky connection. Webhooks are better for these.
</Callout>
