> ## 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.

# Postman

> Import a collection and a sandbox environment generated from openapi.json, then run the calls with built-in checks.

Two files, generated from [`openapi.json`](/openapi.json), let you run every endpoint from Postman or from Newman.

| File | Contents |
| - | - |
| `sahl-partner-api.postman_collection.json` | Collection v2.1: seven requests with fake data, saved example responses for the usual statuses (200, 400, 401, 403, 404, 413, 422, 429, 502 where the call can return them), bearer auth on `{{apiKey}}`, and short test scripts. |
| `sahl-sandbox.postman_environment.json` | Environment "Sahl sandbox": `baseUrl`, `apiKey` (empty, secret), `environment` (`sandbox`), `reference` (`client-0001`). |

No key and no document is inside either file.

Text copies for import by link: [collection](/postman/sahl-partner-api.postman_collection.json.txt) and [environment](/postman/sahl-sandbox.postman_environment.json.txt). They hold the same JSON. The `.json` files are in the `postman/` folder of the documentation package.

## Import

1. Open Postman. Click **Import**.
2. Import the collection. Choose one way:
   * **Link**: paste `https://docs.sahlfinancial.com/postman/sahl-partner-api.postman_collection.json.txt`.
   * **File**: choose the downloaded `sahl-partner-api.postman_collection.json`.
   * **Raw text**: open the text copy above, select all, paste.
3. Import the environment the same way. Its content is small enough to paste here:

```json theme={null}
{
  "id": "a85c6911-a553-5571-a8ac-05c299d21326",
  "name": "Sahl sandbox",
  "values": [
    {
      "key": "baseUrl",
      "value": "https://app.sahlfinancial.com/api",
      "type": "default",
      "enabled": true
    },
    {
      "key": "apiKey",
      "value": "",
      "type": "secret",
      "enabled": true
    },
    {
      "key": "environment",
      "value": "sandbox",
      "type": "default",
      "enabled": true
    },
    {
      "key": "reference",
      "value": "client-0001",
      "type": "default",
      "enabled": true
    }
  ],
  "_postman_variable_scope": "environment",
  "_postman_exported_using": "sahl-docs"
}
```

4. Select **Sahl sandbox** in the environment menu at the top right.
5. Open the environment and set **Current value** of `apiKey` to your own key. Use the current value, not the initial value: Postman keeps current values on your machine and can sync initial values to a shared workspace. Create the key as described in [Test in the sandbox](/test-in-sandbox#step-1-create-a-sandbox-key).

Leave `environment` as `sandbox`. `baseUrl` is `https://app.sahlfinancial.com/api`.

## The requests

Run them in order. Each stores what the next one needs.

| # | Request | Sends | Test script asserts | Stores |
| - | - | - | - | - |
| 1 | Read a payslip | `POST /v1/kyc/extract`, form-data: `files`, `doc_type=payslip`, `reference`, `environment`, `subject`, `kind` | HTTP 200; the answer has `fields`, `documents`, `field_count`, `checks`, `reader_unavailable`, `policy`; `reader_unavailable` is false | `documents_payslip`, `caseId` |
| 2 | Read a national ID (CIN) | `POST /v1/kyc/extract` with `doc_type=national_id` | Same | `documents_id`, `caseId` |
| 3 | Verify a profile | `POST /v1/kyc/verify`, JSON with `values` and the stored `documents` | HTTP 200; `passed` is a boolean; `checks` is an array; the answer has `case_id` | `caseId` |
| 4 | Assess risk | `POST /v1/kyc/assess`, JSON with the same documents and the suitability answers | HTTP 200; the answer has `verification`, `assessment`, `registry`; compliance level is `Low`, `Medium` or `High` | |
| 5 | eID: start a check | `POST /v1/kyc/eid` | HTTP 201; `key` is a number | `eidKey` |
| 6 | eID: get the result | `GET /v1/kyc/eid/{key}?environment=sandbox` | HTTP 200; `complete` and `passed` are booleans | |
| 7 | eID: download the PDF report | `GET /v1/kyc/eid/{key}/report` | HTTP 200; `Content-Type` is `application/pdf` | |

Before each request a collection script checks that `apiKey` is set, and adds a fresh `X-Request-ID` (a GUID) so you can find the call in **Developers, Call log** in the console.

<Warning>
  Requests 5 to 7 start a real eID check and email the client, even in sandbox. Skip them unless your workspace has an eID provider account, and replace the email in the body with an address you control.
</Warning>

### Files for requests 1 and 2

The collection holds no document. In requests 1 and 2, open the **Body** tab and click the `files` row to choose your own fake test file. The collection refers to them as `payslip-test.pdf` and `cin-test.jpg` as placeholders. Make the files yourself with invented data and do not upload a real client document: see [Sandbox](/sandbox#making-a-fake-client-that-behaves).

### Variables

| Variable | Scope | Use |
| - | - | - |
| `baseUrl` | environment | `https://app.sahlfinancial.com/api` |
| `apiKey` | environment, secret | Your key. Empty in the file. |
| `environment` | environment | `sandbox`. Sent as the `environment` field. |
| `reference` | environment | `client-0001`. Your id for the client. Change it to start another case. |
| `documents`, `documents_id`, `documents_payslip`, `caseId`, `eidKey` | collection | Filled by the scripts. |

Request 3 and 4 put `{{documents}}` in the JSON body. Postman's editor may underline it as invalid JSON before the run. It is replaced by the entries from requests 1 and 2 when you send.

## What the scripts do

All scripts are plain Postman sandbox code. Request 1:

```javascript theme={null}
pm.test("status is 200", function () { pm.response.to.have.status(200); });
const body = pm.response.json();
pm.test("answer has the documented keys", function () {
  ["fields", "documents", "field_count", "checks", "reader_unavailable", "policy"].forEach(function (k) { pm.expect(body).to.have.property(k); });
});
pm.test("the file was read", function () { pm.expect(body.reader_unavailable).to.eql(false); });
pm.collectionVariables.set("documents_payslip", JSON.stringify(body.documents));
if (body.case_id) { pm.collectionVariables.set("caseId", body.case_id); }
```

Request 3 first joins the stored entries:

```javascript theme={null}
const parts = ["documents_id", "documents_payslip"].map(function (k) { return JSON.parse(pm.collectionVariables.get(k) || "[]"); });
pm.collectionVariables.set("documents", JSON.stringify([].concat(parts[0], parts[1])));
```

A failing verdict is still HTTP 200, so a test that asserts 200 passes when `passed` is false. Add your own assertion if you want a failing run to fail the pipeline, for example `pm.expect(body.passed).to.eql(true)`.

## Run from the command line with Newman

```bash theme={null}
npm install -g newman
newman run sahl-partner-api.postman_collection.json \
  -e sahl-sandbox.postman_environment.json \
  --env-var "apiKey=$SAHL_API_KEY" \
  --working-dir ./samples \
  --folder "1. Read a payslip" --folder "2. Read a national ID (CIN)" \
  --folder "3. Verify a profile" --folder "4. Assess risk"
```

Put `payslip-test.pdf` and `cin-test.jpg` in `./samples`. `--folder` is given the request names here so that the eID requests are skipped. The collection and its scripts were run with Newman against a local stand-in server, not against the live API.


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