---
title: "Create a terms session"
method: POST
path: "/customers/terms-sessions"
tags: ["Customers"]
---

# Create a terms session

`POST /customers/terms-sessions`

## Request

- Base URL: `https://developers.ozav.io/v2`
- URL: `https://developers.ozav.io/v2/customers/terms-sessions`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Creates a terms-of-service session. Customer provisioning at a settlement
partner is fail-closed on an accepted terms session: `POST /customers`
returns `422 TERMS_ACCEPTANCE_REQUIRED` until you submit the
`terms_session_id` of a session that has been accepted.

The response carries `id` - the session token - **once, at creation**.
OZAV stores only its hash, so it is never returned again. Persist it
before you present the terms to your end user.

Present `terms_url` to the end user, collect their acceptance in your own
flow, then record it with `POST /customers/terms-sessions/accept`.
Sessions expire; `expires_at` is absolute.

Accepts an optional `Idempotency-Key`. Replaying the same key returns the
same session **without** `id` - the token is only ever issued once.

## Headers

- `Idempotency-Key` string

## Response `200`

Idempotent replay - the same session, without the token

- TermsSession: A terms-of-service session. Customer provisioning at a settlement partner is fail-closed on one of these being accepted.
  - `id` string: The session token, prefixed `ts_`. Returned only on creation - OZAV stores just its hash. Persist it; it is never returned again, not even on an idempotent replay.
  - `object` 'terms_session', required
  - `status` 'pending' | 'accepted', required: `pending` until you record the acceptance; only `accepted` satisfies `POST /customers`. There is no hosted page in between, so there is no intermediate state.
  - `terms_url` string, uri, required: The terms to present to your end user.
  - `terms_version` string, required: The version in force when the session was created. Acceptance is recorded against this version, not the current one.
  - `expires_at` string, date-time, required
  - `accepted_at` string, date-time: Present once the acceptance has been recorded.

## Other responses

- `201`: Terms session created
- `400`: The request is invalid.
- `401`: Missing or invalid API key.
- `403`: The organization lacks the entitlement (code ENTITLEMENT_REQUIRED) or the key lacks the scope (code INSUFFICIENT_SCOPE). On money-moving requests (POST /transfers, POST /wallets/{wallet_id}/transfers) a compliance hold on the customer answers with code COMPLIANCE_HOLD: the hold is reviewed and lifted on OZAV's side; retrying does not clear it. When the only hold is a pause until pending onboarding documents are received, a withdrawal answers CUSTOMER_DOCUMENTS_PENDING instead: send what `requirements` on GET /customers/{id} lists; OZAV lifts the pause after reviewing it. On OZAV Services (live without the platform's KYB), any API outside decisions, screenings, lists and self-custody wallets answers with code PRODUCTION_NOT_ACTIVATED.

---

[API](https://skmtc.dev/ozav/apis/ozav-api.md) - [All operations](https://skmtc.dev/ozav/apis/ozav-api/llms.txt) - [OpenAPI document](https://skmtc.dev/ozav/apis/ozav-api/revisions/4133dc2109d7?raw)
