> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sahlfinancial.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How the calls fit together

> extract, verify, assess and eID: what each call takes, what it returns, and what you pass on.

The Partner API has four jobs and six endpoints. Each call is a function of what you send. Sahl files nothing on your workspace unless the call carries a `reference`.

| Job | Endpoint | Scope | Costs a read |
| - | - | - | - |
| Read documents into fields | `POST /v1/kyc/extract` | `kyc:extract` | Yes, one per file |
| Verify a profile and its documents | `POST /v1/kyc/verify` | `kyc:verify` | No |
| Verify, then assess risk | `POST /v1/kyc/assess` | `kyc:verify` | No |
| Check a Canadian client remotely | `POST /v1/kyc/eid`, `GET /v1/kyc/eid/{key}`, `GET /v1/kyc/eid/{key}/report` | `kyc:eid` | No |

Only `/extract` calls the vision model, so only `/extract` is metered. The allowance is checked before any file is read.

## The main path

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant App as Your server
    participant API as Sahl Partner API
    participant Console as Sahl console
    App->>API: POST /v1/kyc/extract (files, doc_type, reference)
    API-->>App: fields, documents[], checks[], case_id
    App->>API: POST /v1/kyc/extract (next document)
    API-->>App: fields, documents[], checks[]
    Note over App: Merge the fields you hold into values.<br/>Keep the documents[] entries unchanged.
    App->>API: POST /v1/kyc/verify (reference, values, documents[])
    API-->>App: passed, checks[], flags[], completeness, case_id
    App->>API: POST /v1/kyc/assess (same body)
    API-->>App: verification, assessment, case_id
    API-->>Console: case, documents and verdict filed under reference
```

What you pass from one call to the next:

| From | To | What |
| - | - | - |
| `/extract` answer `documents[]` | `/verify` and `/assess` request `documents` | Each entry unchanged, including `step_key` and `document_id`. |
| `/extract` answer `fields` | Your own form or database | Pre-fill. You decide which values go into `values`. |
| Your own data | `/verify` and `/assess` request `values` | Names, dates, address, income, suitability answers. |
| The same `reference` | Every call | It ties the calls to one case. |

`/assess` takes the same body as `/verify` and runs the same verification first. If you want both answers, call `/assess` only: its `verification` key holds the full verdict.

## Why send the entries back

`/verify` does not read files. It checks the `documents[]` entries you send, so it needs what `/extract` saw: the document type, the fields, the file dates and the `step_key`. Without the `step_key` the same document could pass the type check at `/extract` and fail it at `/verify`. The API puts the `step_key` on each entry for that reason.

If you edit an entry, you verify your edit, not the document.

## The eID path

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant App as Your server
    participant API as Sahl Partner API
    participant Provider as eID provider
    participant Client as Your client
    App->>API: POST /v1/kyc/eid (reference, name, email, country=CA)
    API->>Provider: create request
    Provider-->>Client: email with PIN and link
    API-->>App: 201 key, reference
    Client->>Provider: scans ID, takes selfie
    loop until complete is true
        App->>API: GET /v1/kyc/eid/{key}
        API->>Provider: read request
        API-->>App: complete, passed, checks[]
    end
    App->>API: GET /v1/kyc/eid/{key}/report
    API-->>App: PDF
    App->>API: POST /v1/kyc/verify (same reference and environment)
    API-->>App: verdict that meets the policy eID requirement
```

There is no callback from the provider. You poll, and Sahl sends the `kyc.eid_completed` webhook the first time a poll sees the end state. Details are in [eID check](/guides/eid). In this version eID is a Canadian-client feature, so the sample request uses `country=CA`; every other call on this page takes any country, for example `MA`.

## Case life cycle

A case exists once per workspace, environment and `reference`. Each call with that reference updates it.

```mermaid theme={null}
flowchart LR
    A[First call with a reference] --> B[Case created]
    B --> C[extract: documents filed]
    C --> D[verify or assess: verdict filed]
    D --> E[eID: result recorded when polled]
    D --> F[Staff review in the console]
    F --> G[approved or refused]
```

A re-verify never overwrites a status a person set: `approved` and `refused` stay.

## Choosing the calls

| You want | Call |
| - | - |
| Only the text and fields of a document | `/extract` |
| A yes or no on a file you already hold the data for | `/verify` with `documents: []` and `require_documents: false` (works when your policy does not lock identity verification) |
| Document checks plus cross-document checks | `/extract` per document, then `/verify` |
| A risk rating for the file | `/assess` |
| Proof that a remote client is the person on the ID | `/eid` |

<Note>
  The API has no idempotency key and no batch endpoint. Sending the same call twice reads the files twice and counts two reads, and files a second set of documents on the case. See [Errors and retries](/errors#retries).
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.