# Extraction API reference

> The extraction operations of the Fax for Agents API. Read a received fax or a document with OCR, extract fields against a schema, classify it and summarise it.

Page: https://faxforagents.com/docs/api/reference/extractions/
Last changed: 2026-11-13

Updated Nov 13, 2026

13 operations of the Fax for Agents API, from the OpenAPI document version 1.20.0, snapshot of 2026-11-13. The base URL is `https://api.faxforagents.com/v1`. This is one group of the [full reference](https://faxforagents.com/docs/api/reference/).

- A reviewer's correction is stored beside the extraction and is never merged into it.
- Saving an extraction schema under a name that exists creates the next version of it.
- Every sentence of a document summary cites the pages it comes from.

## Operations

- `GET /v1/classifications` Classifications, newest first
- `POST /v1/classifications` Classify a received fax or a document into one of your document types, or abstain
- `GET /v1/classifications/{classification_id}` One classification
- `GET /v1/document-summaries` Summaries, newest first
- `POST /v1/document-summaries` Summarise a received fax or a document; every sentence cites its pages
- `GET /v1/document-summaries/{summary_id}` One summary
- `GET /v1/extraction-schemas` Your extraction schemas
- `POST /v1/extraction-schemas` Save a versioned extraction schema (the same name again is the next version)
- `GET /v1/extraction-schemas/{schema_id}` One schema version
- `GET /v1/extractions` Extractions, newest first
- `POST /v1/extractions` Read a received fax or a document: OCR per page, then fields against a schema
- `GET /v1/extractions/{extraction_id}` One extraction with its corrections
- `POST /v1/extractions/{extraction_id}/corrections` Record a reviewer's correction of one field (stored beside the extraction, never merged)

## What can the extraction group read?

A received fax or a document of yours. Each create call takes an `inbox_item_id` or a `document_id`. There are three kinds of result, and each has its own create, list and read operations.

An extraction runs OCR page by page and then fills fields against a schema. A classification puts the input into one of your document types, or abstains. A summary condenses the input, and every sentence cites its pages. All three answer in one shape, so a client reads `status`, `output`, `confidence` and `pages` the same way for each.

## How does an extraction use a schema?

`POST /v1/extractions` takes a schema in one of two ways. `schema` is inline. The OpenAPI document describes it as a JSON Schema object of string, number, boolean or date fields with descriptions. `schema_id` names a saved one.

`POST /v1/extraction-schemas` saves a schema with a name and a description. Saving the same name again creates the next version, and the earlier version stays readable by its id. An extraction made with a version keeps pointing at that version.

## Which options control cost and coverage?

`max_pages` caps how many pages are read. `strict` changes what happens when the document is longer than that cap. With it the call is refused with `page_limit_exceeded`. Without it the first pages are read and the result says how many, in `pages_requested` and `pages_processed`.

`strong_model_if_below` is a confidence threshold. A page that scores under it is read again by the stronger model, and `pages_escalated` counts those pages. A classification also takes `document_types`, the list to choose from, and `abstain_below`, the confidence under which it answers no type.

The result carries `price_micro` and the models that ran. A create call answers 402 when the wallet cannot cover the pages. The [receive guide](https://faxforagents.com/docs/receive-fax/#how-do-i-read-the-text-of-a-fax) has the prices with their date.

## How do corrections work?

`POST /v1/extractions/{extraction_id}/corrections` records one reviewer's correction of one field, with the value and a note. The correction is stored beside the extraction and never merged. The model's output stays as it was produced, and the read of an extraction returns it with its corrections. That keeps a record of what the model said and what a person changed.

## Is extracted text safe to act on?

Treat it as data. The text of a fax was written by whoever sent the fax. An agent that reads it must not take a destination, an approval or an instruction from it. The API returns the text and the fields. What your code does with them is your decision, and the safe rule is that the text never chooses the next send.

## Which scope does the group need?

One. Every operation here needs `document:extract`, the reads and the lists included. The lists filter by `inbox_item_id` or `document_id` and page with `cursor` and `limit`, newest first.

Test keys run on the sandbox engine, which has no model behind it and costs nothing. It returns the shape, so a client can be built against it before the first live page.

## Each operation in detail

### GET `/v1/classifications`

Classifications, newest first

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

GET /v1/classifications parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `inbox_item_id` | query | string or null | no |  |
| `document_id` | query | string or null | no |  |
| `cursor` | query | string or null | no |  |
| `limit` | query | integer | no | Default `50` . |

#### Responses

GET /v1/classifications responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/classifications response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | array of object Extraction | yes |  |
| `next_cursor` | string or null | no |  |

#### Example

```
`curl https://api.faxforagents.com/v1/classifications \ -H "Authorization: Bearer ffa_test_..."`
```

### POST `/v1/classifications`

Classify a received fax or a document into one of your document types, or abstain

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

POST /v1/classifications parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |

#### Request body application/json, required

POST /v1/classifications request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `abstain_below` | number | no |  |
| `document_id` | string or null | no |  |
| `document_types` | array of string | yes |  |
| `inbox_item_id` | string or null | no |  |
| `max_pages` | integer or null | no |  |
| `strict` | boolean | no | Refuse with page_limit_exceeded when the document has more pages than would be read, instead of reading the first ones and warning. |
| `strong_model_if_below` | number | no |  |

#### Responses

POST /v1/classifications responses

| Status | Meaning |
| --- | --- |
| `201` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `402` | The prepaid balance does not cover the call: insufficient_balance. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `409` | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

POST /v1/classifications response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `completed_at` | string or null | yes |  |
| `confidence` | number or null | yes |  |
| `corrections` | array of object or null | no |  |
| `created_at` | string | yes |  |
| `created_by` | string | yes |  |
| `currency` | string | yes |  |
| `document_id` | string | yes |  |
| `document_pages` | integer | yes | The document's page count. Above pages_processed on a completed row means the cap left pages unread; output.truncated and a warning say so. |
| `environment` | string (live, test) | yes |  |
| `error_code` | string or null | yes |  |
| `id` | string | yes |  |
| `inbox_item_id` | string or null | yes |  |
| `kind` | string (extract, classify, summarize) | yes |  |
| `models` | object | yes |  |
| `options` | object | yes |  |
| `output` | object or null | yes |  |
| `pages` | array of object ExtractionPage | yes |  |
| `pages_escalated` | integer | yes |  |
| `pages_processed` | integer | yes |  |
| `pages_requested` | integer | yes |  |
| `price_micro` | integer | yes |  |
| `schema` | object or null | no |  |
| `schema_id` | string or null | yes |  |
| `started_at` | string or null | yes |  |
| `status` | string (pending, queued, running, completed, failed) | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/classifications \ -X POST \ -H "Authorization: Bearer ffa_test_..." \ -H "Content-Type: application/json" \ -d '{"document_types":["example"]}'`
```

### GET `/v1/classifications/{classification_id}`

One classification

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

GET /v1/classifications/{classification_id} parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `classification_id` | path | string | yes |  |

#### Responses

GET /v1/classifications/{classification_id} responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/classifications/{classification_id} response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `completed_at` | string or null | yes |  |
| `confidence` | number or null | yes |  |
| `corrections` | array of object or null | no |  |
| `created_at` | string | yes |  |
| `created_by` | string | yes |  |
| `currency` | string | yes |  |
| `document_id` | string | yes |  |
| `document_pages` | integer | yes | The document's page count. Above pages_processed on a completed row means the cap left pages unread; output.truncated and a warning say so. |
| `environment` | string (live, test) | yes |  |
| `error_code` | string or null | yes |  |
| `id` | string | yes |  |
| `inbox_item_id` | string or null | yes |  |
| `kind` | string (extract, classify, summarize) | yes |  |
| `models` | object | yes |  |
| `options` | object | yes |  |
| `output` | object or null | yes |  |
| `pages` | array of object ExtractionPage | yes |  |
| `pages_escalated` | integer | yes |  |
| `pages_processed` | integer | yes |  |
| `pages_requested` | integer | yes |  |
| `price_micro` | integer | yes |  |
| `schema` | object or null | no |  |
| `schema_id` | string or null | yes |  |
| `started_at` | string or null | yes |  |
| `status` | string (pending, queued, running, completed, failed) | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/classifications/CLASSIFICATION_ID \ -H "Authorization: Bearer ffa_test_..."`
```

### GET `/v1/document-summaries`

Summaries, newest first

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

GET /v1/document-summaries parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `inbox_item_id` | query | string or null | no |  |
| `document_id` | query | string or null | no |  |
| `cursor` | query | string or null | no |  |
| `limit` | query | integer | no | Default `50` . |

#### Responses

GET /v1/document-summaries responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/document-summaries response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | array of object Extraction | yes |  |
| `next_cursor` | string or null | no |  |

#### Example

```
`curl https://api.faxforagents.com/v1/document-summaries \ -H "Authorization: Bearer ffa_test_..."`
```

### POST `/v1/document-summaries`

Summarise a received fax or a document; every sentence cites its pages

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

POST /v1/document-summaries parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |

#### Request body application/json, required

POST /v1/document-summaries request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string or null | no |  |
| `inbox_item_id` | string or null | no |  |
| `max_pages` | integer or null | no |  |
| `strict` | boolean | no | Refuse with page_limit_exceeded when the document has more pages than would be read, instead of reading the first ones and warning. |
| `strong_model_if_below` | number | no |  |

#### Responses

POST /v1/document-summaries responses

| Status | Meaning |
| --- | --- |
| `201` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `402` | The prepaid balance does not cover the call: insufficient_balance. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `409` | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

POST /v1/document-summaries response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `completed_at` | string or null | yes |  |
| `confidence` | number or null | yes |  |
| `corrections` | array of object or null | no |  |
| `created_at` | string | yes |  |
| `created_by` | string | yes |  |
| `currency` | string | yes |  |
| `document_id` | string | yes |  |
| `document_pages` | integer | yes | The document's page count. Above pages_processed on a completed row means the cap left pages unread; output.truncated and a warning say so. |
| `environment` | string (live, test) | yes |  |
| `error_code` | string or null | yes |  |
| `id` | string | yes |  |
| `inbox_item_id` | string or null | yes |  |
| `kind` | string (extract, classify, summarize) | yes |  |
| `models` | object | yes |  |
| `options` | object | yes |  |
| `output` | object or null | yes |  |
| `pages` | array of object ExtractionPage | yes |  |
| `pages_escalated` | integer | yes |  |
| `pages_processed` | integer | yes |  |
| `pages_requested` | integer | yes |  |
| `price_micro` | integer | yes |  |
| `schema` | object or null | no |  |
| `schema_id` | string or null | yes |  |
| `started_at` | string or null | yes |  |
| `status` | string (pending, queued, running, completed, failed) | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/document-summaries \ -X POST \ -H "Authorization: Bearer ffa_test_..." \ -H "Content-Type: application/json" \ -d '{}'`
```

### GET `/v1/document-summaries/{summary_id}`

One summary

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

GET /v1/document-summaries/{summary_id} parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `summary_id` | path | string | yes |  |

#### Responses

GET /v1/document-summaries/{summary_id} responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/document-summaries/{summary_id} response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `completed_at` | string or null | yes |  |
| `confidence` | number or null | yes |  |
| `corrections` | array of object or null | no |  |
| `created_at` | string | yes |  |
| `created_by` | string | yes |  |
| `currency` | string | yes |  |
| `document_id` | string | yes |  |
| `document_pages` | integer | yes | The document's page count. Above pages_processed on a completed row means the cap left pages unread; output.truncated and a warning say so. |
| `environment` | string (live, test) | yes |  |
| `error_code` | string or null | yes |  |
| `id` | string | yes |  |
| `inbox_item_id` | string or null | yes |  |
| `kind` | string (extract, classify, summarize) | yes |  |
| `models` | object | yes |  |
| `options` | object | yes |  |
| `output` | object or null | yes |  |
| `pages` | array of object ExtractionPage | yes |  |
| `pages_escalated` | integer | yes |  |
| `pages_processed` | integer | yes |  |
| `pages_requested` | integer | yes |  |
| `price_micro` | integer | yes |  |
| `schema` | object or null | no |  |
| `schema_id` | string or null | yes |  |
| `started_at` | string or null | yes |  |
| `status` | string (pending, queued, running, completed, failed) | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/document-summaries/SUMMARY_ID \ -H "Authorization: Bearer ffa_test_..."`
```

### GET `/v1/extraction-schemas`

Your extraction schemas

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Responses

GET /v1/extraction-schemas responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/extraction-schemas response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | array of object ExtractionSchema | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/extraction-schemas \ -H "Authorization: Bearer ffa_test_..."`
```

### POST `/v1/extraction-schemas`

Save a versioned extraction schema (the same name again is the next version)

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

POST /v1/extraction-schemas parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |

#### Request body application/json, required

POST /v1/extraction-schemas request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `description` | string or null | no |  |
| `name` | string | yes |  |
| `schema` | object | yes |  |

#### Responses

POST /v1/extraction-schemas responses

| Status | Meaning |
| --- | --- |
| `201` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `409` | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

POST /v1/extraction-schemas response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `created_at` | string | yes |  |
| `created_by` | string | yes |  |
| `description` | string or null | yes |  |
| `id` | string | yes |  |
| `name` | string | yes |  |
| `schema` | object | yes |  |
| `status` | string | yes |  |
| `version` | integer | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/extraction-schemas \ -X POST \ -H "Authorization: Bearer ffa_test_..." \ -H "Content-Type: application/json" \ -d '{"name":"example","schema":{}}'`
```

### GET `/v1/extraction-schemas/{schema_id}`

One schema version

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

GET /v1/extraction-schemas/{schema_id} parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `schema_id` | path | string | yes |  |

#### Responses

GET /v1/extraction-schemas/{schema_id} responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/extraction-schemas/{schema_id} response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `created_at` | string | yes |  |
| `created_by` | string | yes |  |
| `description` | string or null | yes |  |
| `id` | string | yes |  |
| `name` | string | yes |  |
| `schema` | object | yes |  |
| `status` | string | yes |  |
| `version` | integer | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/extraction-schemas/SCHEMA_ID \ -H "Authorization: Bearer ffa_test_..."`
```

### GET `/v1/extractions`

Extractions, newest first

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

GET /v1/extractions parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `inbox_item_id` | query | string or null | no |  |
| `document_id` | query | string or null | no |  |
| `cursor` | query | string or null | no |  |
| `limit` | query | integer | no | Default `50` . |

#### Responses

GET /v1/extractions responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/extractions response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | array of object Extraction | yes |  |
| `next_cursor` | string or null | no |  |

#### Example

```
`curl https://api.faxforagents.com/v1/extractions \ -H "Authorization: Bearer ffa_test_..."`
```

### POST `/v1/extractions`

Read a received fax or a document: OCR per page, then fields against a schema

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

POST /v1/extractions parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |

#### Request body application/json, required

POST /v1/extractions request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string or null | no |  |
| `inbox_item_id` | string or null | no |  |
| `max_pages` | integer or null | no |  |
| `schema` | object or null | no | A JSON Schema object of string, number, boolean or date fields with descriptions. |
| `schema_id` | string or null | no |  |
| `strict` | boolean | no | Refuse with page_limit_exceeded when the document has more pages than would be read, instead of reading the first ones and warning. |
| `strong_model_if_below` | number | no |  |

#### Responses

POST /v1/extractions responses

| Status | Meaning |
| --- | --- |
| `201` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `402` | The prepaid balance does not cover the call: insufficient_balance. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `409` | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

POST /v1/extractions response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `completed_at` | string or null | yes |  |
| `confidence` | number or null | yes |  |
| `corrections` | array of object or null | no |  |
| `created_at` | string | yes |  |
| `created_by` | string | yes |  |
| `currency` | string | yes |  |
| `document_id` | string | yes |  |
| `document_pages` | integer | yes | The document's page count. Above pages_processed on a completed row means the cap left pages unread; output.truncated and a warning say so. |
| `environment` | string (live, test) | yes |  |
| `error_code` | string or null | yes |  |
| `id` | string | yes |  |
| `inbox_item_id` | string or null | yes |  |
| `kind` | string (extract, classify, summarize) | yes |  |
| `models` | object | yes |  |
| `options` | object | yes |  |
| `output` | object or null | yes |  |
| `pages` | array of object ExtractionPage | yes |  |
| `pages_escalated` | integer | yes |  |
| `pages_processed` | integer | yes |  |
| `pages_requested` | integer | yes |  |
| `price_micro` | integer | yes |  |
| `schema` | object or null | no |  |
| `schema_id` | string or null | yes |  |
| `started_at` | string or null | yes |  |
| `status` | string (pending, queued, running, completed, failed) | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/extractions \ -X POST \ -H "Authorization: Bearer ffa_test_..." \ -H "Content-Type: application/json" \ -d '{}'`
```

### GET `/v1/extractions/{extraction_id}`

One extraction with its corrections

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

GET /v1/extractions/{extraction_id} parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `extraction_id` | path | string | yes |  |

#### Responses

GET /v1/extractions/{extraction_id} responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/extractions/{extraction_id} response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `completed_at` | string or null | yes |  |
| `confidence` | number or null | yes |  |
| `corrections` | array of object or null | no |  |
| `created_at` | string | yes |  |
| `created_by` | string | yes |  |
| `currency` | string | yes |  |
| `document_id` | string | yes |  |
| `document_pages` | integer | yes | The document's page count. Above pages_processed on a completed row means the cap left pages unread; output.truncated and a warning say so. |
| `environment` | string (live, test) | yes |  |
| `error_code` | string or null | yes |  |
| `id` | string | yes |  |
| `inbox_item_id` | string or null | yes |  |
| `kind` | string (extract, classify, summarize) | yes |  |
| `models` | object | yes |  |
| `options` | object | yes |  |
| `output` | object or null | yes |  |
| `pages` | array of object ExtractionPage | yes |  |
| `pages_escalated` | integer | yes |  |
| `pages_processed` | integer | yes |  |
| `pages_requested` | integer | yes |  |
| `price_micro` | integer | yes |  |
| `schema` | object or null | no |  |
| `schema_id` | string or null | yes |  |
| `started_at` | string or null | yes |  |
| `status` | string (pending, queued, running, completed, failed) | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/extractions/EXTRACTION_ID \ -H "Authorization: Bearer ffa_test_..."`
```

### POST `/v1/extractions/{extraction_id}/corrections`

Record a reviewer's correction of one field (stored beside the extraction, never merged)

Credential: an API key or a signed-in session. Scope: `document:extract`.

#### Parameters

POST /v1/extractions/{extraction_id}/corrections parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `extraction_id` | path | string | yes |  |
| `Idempotency-Key` | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |

#### Request body application/json, required

POST /v1/extractions/{extraction_id}/corrections request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `field` | string or null | no |  |
| `note` | string or null | no |  |
| `value` | any | no |  |

#### Responses

POST /v1/extractions/{extraction_id}/corrections responses

| Status | Meaning |
| --- | --- |
| `201` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `409` | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

POST /v1/extractions/{extraction_id}/corrections response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `created_at` | string | yes |  |
| `created_by` | string | yes |  |
| `extraction_id` | string | yes |  |
| `field` | string | yes |  |
| `id` | string | yes |  |
| `note` | string or null | yes |  |
| `value` | any | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/extractions/EXTRACTION_ID/corrections \ -X POST \ -H "Authorization: Bearer ffa_test_..." \ -H "Content-Type: application/json" \ -d '{}'`
```
