# Standalone APIs

Each check also runs on its own, server to server, without a session or the hosted page: you send the images or file, secuveri answers. They use the same models and rules as the workflow steps, are charged per call at the step's price (Billing shows them under API calls), and need the product's API key scope. AML screening (above) works the same way.

| Call | Answer | Charged |
| --- | --- | --- |
| `POST /v1/face/match` | Synchronous: MATCH / NO_MATCH with the similarity score | CHF 0.30 per answer |
| `POST /v1/liveness/check` | Synchronous: LIVE / SPOOF / REVIEW, passive | CHF 0.60 per answer |
| `POST /v1/age/estimate` | Synchronous: estimated age, OVER_THRESHOLD / NOT_CONFIRMED | CHF 0.30 per answer |
| `POST /v1/content-credentials/check` | Synchronous: the C2PA verdict and summary | CHF 0.05 per checked file |
| `POST /v1/documents/verify` | Asynchronous: document type, fields, MRZ check digits, authenticity | CHF 1.20 per document read |
| `POST /v1/proof-of-address/read` | Asynchronous: name match, address, issue date, issuer, forensics | CHF 0.25 per file read |
| `POST /v1/kyb/cases` | Asynchronous: a Swiss company from the register, its persons and owners (see Business verification above) | Per company found |

- Send `multipart/form-data` with file fields, or JSON with each file as a base64 string. Files are checked by their bytes, not their name: images are JPEG, PNG or WebP (C2PA also HEIC, HEIF and AVIF), proof of address may be a PDF.
- A `sk_test_` key returns a fixed test answer without running a model and is never charged. Pick the answer with `sandbox_outcome`. A `sk_live_` key needs your organization to be live.
- Charged only when the check answered; when it could not run on our side (a model or validator down, a timeout) the call answers 503 and is refunded.
- Send `Idempotency-Key` to make retries safe: for 24 hours the same key and request return the saved answer and `check_id` without a second charge.
- The answer carries `signed_result`, the same answer as an ES256 JWS you can verify with `/.well-known/jwks.json`.
- Images and files are not stored. Synchronous checks keep them only in memory; document photos are erased when the check ends. Asynchronous answers can be read for 24 hours.

```shell
curl -X POST https://api-verify.secuveri.com/v1/face/match \
  -H "x-api-key: $SECUVERI_API_KEY" \
  -H "Idempotency-Key: $REQUEST_ID" \
  -F selfie=@selfie.jpg \
  -F reference=@passport-portrait.jpg \
  -F threshold=0.6
```

```shell
{
  "check_id": "6f1c2c9e-2d4b-4b8e-9a51-2f0d7c3e8a10",
  "product": "face-match",
  "environment": "production",
  "decision": "MATCH",
  "match": true,
  "score": 0.71,
  "threshold": 0.6,
  "sandbox": false,
  "checked_at": "2026-11-01T09:00:00.000Z",
  "signed_result": "eyJhbGciOiJFUzI1NiIs..."
}
```

### Passive liveness is weaker than the hosted flow

`/v1/liveness/check` scores still images with the hosted flow's presentation-attack and deepfake models. It has none of what makes the hosted liveness strong: no random challenge, no screen-flash reflection, no binding of the images to a live capture. It catches printed photos, screens and masks of the kinds the models were trained on; it cannot tell whether the images you send were captured live or replayed. Use it to screen selfies you already have; use a hosted session where a live person must be proven.

### Age estimation and its margin

`/v1/age/estimate` returns the estimate and decides OVER_THRESHOLD only when it reaches `threshold` plus `buffer_years` (default 18 + 7, the hosted gate's pass age of 25). The estimate carries no calibrated error bound; `uncertainty.spread_years` only shows how far estimates over several images differ. Below the pass age the answer is NOT_CONFIRMED, not "under age": check a document then.

### Asynchronous checks

`/v1/documents/verify` and `/v1/proof-of-address/read` answer `202` with a `check_id` and `status: PROCESSING`. Poll `GET /v1/documents/verify/{check_id}` (or `/v1/proof-of-address/read/{check_id}`) or subscribe a webhook endpoint to `documents.verify.completed` / `proof_of_address.read.completed`; `data.check_id` names the check. A check that does not finish within minutes ends FAILED and is refunded. The document check reads the photos as sent: send each side flat and cropped to the document. It does not read the chip (that needs the person's phone) and runs no morph or face checks.

```shell
curl -X POST https://api-verify.secuveri.com/v1/proof-of-address/read \
  -H "x-api-key: $SECUVERI_API_KEY" \
  -F file=@bill.pdf \
  -F given_names=Anna \
  -F surname=Muster \
  -F country=CH \
  -F postcode=8001
```
