Extract structured data
Attach a schema to an inbox and incoming email arrives as validated, typed fields instead of raw text.
Attach a schema to an inbox and every incoming email arrives with the fields you asked for — an order id, a total, a tracking number — already extracted and validated. No parsing, no prompts, no regex on your side.
Attach a schema
PUT /v1/inboxes/{inbox}/schema attaches or replaces the extraction contract, and needs the inboxes:write scope. Address the inbox by id or by its full address.
Schema shape
The schema is a flat map of field name to declaration. A standard JSON Schema also works — { "type": "object", "properties": { … }, "required": [ … ] } is folded into the same shape on write.
- Types:
string,number,integer,boolean,url, andemail— the last two validate their format.objectandarraydeclare nested values. - Per-field keys:
required,default,enum, andmaxLength, applied when an incoming email is validated against the schema. - Size: the whole schema must stay within 8 KiB. An empty schema (
{}, or omitted) means no contract — mail passes through unshaped. extractionHint: an optional plain-English pointer for the extractor, up to 1,000 characters. It is prompt context only, never executed. APUTreplaces the whole contract, so include the hint on every update you want to keep.
Where the data lands
Once a schema is attached, each matching email carries its results on the message record — extractionStatus for the outcome and structured for the extracted object:
The message.received webhook event carries the same result in a structured block, so an event-driven consumer never has to fetch the body to get the fields.
Extracted values are copied from the email, never invented: a required field whose value doesn't actually appear in the message fails validation instead of being filled in with a plausible guess.
When an email doesn't fit
onValidationError decides what happens when an email can't satisfy the schema — say, a confirmation with no order total.
| Value | What happens |
|---|---|
quarantine (default) | The message is stored but held out of your normal flow: no message.received event fires. A message.quarantined event fires instead, carrying the raw candidate and the validation error. |
passthrough | The message is delivered normally, carrying the raw candidate plus the validation error. |
The outcome for any message is readable on its extractionStatus:
| Status | Meaning |
|---|---|
validated | The extraction matched the schema; structured holds the typed object. |
quarantined | Validation failed under quarantine; the message was held aside. |
passthrough | Validation failed under passthrough; the message was delivered with the raw candidate. |
skipped | Extraction didn't run — the inbox had no contract. |
error | Extraction was unavailable; the message was delivered normally, without structured data. |
Read or remove the schema
Check what contract an inbox carries, or detach it to go back to plain, unshaped mail. Reading uses the inboxes:read scope; detaching uses inboxes:write. Reading an inbox that has no schema returns 404; detaching returns 204 with an empty body.
A structured inbox turns "parse the email" into "read the fields." Pair it with the message.received event: when a matching email arrives, the extracted data is already in the payload.
Next steps
- Inboxes — create the inbox a schema attaches to.
- Messages & threads — read the messages your schema shapes.
- Wait for one-time codes — extract one value from one awaited email instead of every email.