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

# Security and data

> What the Partner API does with keys, files and data, as the code does it, and the principles Sahl publishes.

This page has two parts. The first lists facts read from the API code. The second repeats the principles Sahl publishes on [sahlfinancial.com/security](https://sahlfinancial.com/security). That page, the terms, the privacy notice and the DPA clauses are the reference for commitments. This page is not a certification statement.

## Facts from the code

### Keys

| Fact | Detail |
| - | - |
| Storage | Only a SHA-256 hash of the key and a short prefix are stored. The secret is shown once. |
| Scopes | `kyc:extract`, `kyc:verify`, `kyc:eid`. A key carries only what it was issued with. |
| Who manages keys | Tenant admin, API manager and platform admin roles. Creating and rotating a key also needs a verified email. |
| Rotation | A successor with the same name, scopes and binding. The old key expires after a grace period of 0 to 168 hours. |
| Binding | A key can be bound to Google service accounts. Calls then also need a Google-signed identity token in `X-Partner-Identity`. |
| Audit | Creating, revoking and rotating a key write an audit event. A call that reads documents writes the event `partner.documents_read` with the document ids. |

### Isolation

* Every write takes the workspace from the authenticated key. Nothing in the KYC code reads across workspaces.
* An eID request is stored at the provider under a client id made of your workspace id and your reference. Another workspace's key gets 404 for it.
* Cases are separate per environment. Sandbox data never appears in production views.

### Files and data

| Fact | Detail |
| - | - |
| Upload checks | Size cap, pixel cap, a content type allow-list, and a check that the first bytes match the declared type. A polyglot that mixes markup with a PDF header is refused. |
| With a `reference` | The file, the read fields and the checks are stored on your case. Field values are stored because the console shows them. They are not logged and are not put in audit events. |
| Without a `reference` | Nothing is filed on your workspace. The read fields are returned in the response only. |
| Provenance | For each file Sahl reads the creator software, edit dates and revision count from the file metadata, to flag edited documents. |
| Error logs | A failed read logs the kind of failure, never the file name or the document content. |

### Webhooks

* Payloads carry ids, your reference, the environment and a verdict summary. They never carry a field value, a name, a date of birth or a document's contents.
* Deliveries are signed with HMAC-SHA256 and a timestamp. See [Webhooks](/guides/webhooks#verify-the-signature).
* A webhook URL must be https and public. Loopback, private ranges and cloud metadata addresses are refused when you save it and again before each send. The address is resolved once per delivery and the connection goes to that checked address. Redirects are not followed.

### Traffic

* Requests go to `https://app.sahlfinancial.com/api`. The API refuses requests that do not come through Sahl's own front door (403 `direct_access_refused`).
* 100 requests a minute per client IP on these routes.
* Each key call is logged with route, method, status, latency, `X-Request-ID`, reference, environment and error code. The log is kept 90 days by default. Request and response bodies are not part of that record.
* Cross-origin browser calls are accepted only from origins on Sahl's allow-list.

### Retention

* Each workspace has a retention setting (`retention_days`, 90 by default in the data model). A retention routine removes, for documents older than that, the raw file, page images, OCR text, extracted field values, validation messages and review corrections. It keeps the rows (ids, statuses, timestamps, scores, counts) so billing and history still add up, and the append-only audit log.
* A tenant admin can erase or export one case for a data-subject request.
* The `record_retention_days` value in a KYC policy records your retention commitment (for example 1,825 days for the FINTRAC preset). It does not delete anything by itself.
* For an eID check the provider deletes the client's personal details about seven days after the check. Fetch the result and the PDF before that.

Ask Sahl how retention is set and run on your workspace. The routine is part of the code; this documentation does not state a schedule for it.

## Principles Sahl publishes

| Principle | What it says |
| - | - |
| Consent-first access | Data access begins with explicit authorization and can be revoked. |
| Minimized data | We pull and process only what is needed for the approved purpose. |
| Encryption | Industry-standard protections in transit and at rest. |
| Least privilege | Strict access controls for people and systems. |
| Monitoring and traceability | Logs and audit trails support accountability. |
| Secure SDLC | Review, testing, change control, and vulnerability management. |
| Vendor governance | Sub-processors are assessed and contractually bound. |
| Incident readiness | Documented playbooks and communication paths. |
| CNDP posture | Formal declarations and transfer governance. |

## Report a security issue

Write to Sahl and quote the `X-Request-ID` of any call involved. Do not send keys or client data in the message.


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