documentation

How it works

The three messages, the lifecycle of a snap, and what is kept afterwards.

# How it works

One signed request goes in. A snap id comes back before anything is read, and the JSON
follows when the read is done.

The reading happens on our side, after your request has already returned. You never wait on
a model inside a request, and there is nothing to keep alive.

## The three messages

1. **You → us.** `POST /partner/v1/snaps`, with your project's key in
   `Authorization: Bearer s2j_…` and nothing else.
2. **Us → you.** `202 Accepted` and a snap id. Milliseconds, not seconds.
3. **Us → you.** The result, once the page has been read and validated against your schema.

```sequence

```

## Watching a read

A snap moves through four status words:

| Status       | Means                                                   |
| ------------ | ------------------------------------------------------- |
| `REGISTERED` | Accepted and queued. Nothing has been read yet.         |
| `EXECUTING`  | The page is being read and validated.                   |
| `COMPLETED`  | The result is ready, with any violations listed.        |
| `FAILED`     | The read did not produce a result. Nothing is returned. |

Poll the snap until the status is terminal, `COMPLETED` or `FAILED`, or configure a
webhook and let us post it. The console's usage numbers count the same reads, because they
are the core's own totals.

## What is kept

The image is not stored. What stays behind is a hash of the upload and the result. That is
enough to recognise a re-sent document, and not enough to reconstruct the page.

## Tracing

Every call carries a trace id, `traceparent` included, from the console through the core. A
support question that starts with a trace id starts with the answer: the console logs the
same id against the request that produced it.

## Limits you can check before a round trip

- Upload: up to 10 MiB per image.
- Rate: a credential carries its own limit, up to 100,000 requests a minute.
- Schema: up to 10 additional prompts of 500 characters each.

The console refuses a request it knows the core will refuse, and the core enforces the same
numbers again. The full contract lives in `app/constants/index.ts` on our side; for the
public surface, read the OpenAPI document.