---
title: "Create Self Service Tenant"
method: POST
path: "/v1/onboarding/tenants"
tags: ["onboarding"]
---

# Create Self Service Tenant

`POST /v1/onboarding/tenants`

## Request

- Base URL: `https://api.4chems.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.4chems.com/v1/onboarding/tenants`
- Auth: HTTP bearer

Create a 7-day trial tenant for the caller's business email domain (UC-052).
Needs a verified email on a business domain and `attestation: true`; answers
`auth.email_not_verified`, `tenant.attestation_required`,
`tenant.free_mail_domain` (free-mail address), `tenant.domain_exists`
(a live trial tenant on the domain) or `trial.exists_for_domain` (the
domain already had its one trial; call `start_inquiry`). The trial lasts
exactly 7 days; `ttl` / `expires_at` in the body are ignored.

Domain is derived from the verified token email claim (NFR-006 pt 4).
The caller becomes trial admin; the tenant is trial by construction
(UC-044 flavour, ≤7-day expiry, guaranteed teardown) and cannot be
made permanent via this endpoint.

Guard order (nothing persisted on any failure):
  1. email_verified gate (NFR-006 pt 3)
  2. attestation=true (NFR-006 §8a)
  3. per-principal rate limit (NFR-002 pt 2, ≤10/min)
  4. free-mail domain block (NFR-006 pt 5)
  5. live-tenant guard, then trial-once (UC-099) — no re-trial after teardown

## Request body

- SelfServiceTenantCreateIn: Request body for POST /v1/onboarding/tenants (UC-052). The domain is derived from the caller's verified token email claim (NFR-006 pt 4) — it is not a request parameter. attestation must be true; the endpoint raises 422 if false (NFR-006 §8a).
  - `legal_entity` LegalEntityIn, required: Composite legal-entity input validated against the country catalog. Rules: - *country* must be a supported market (validated at field level via SupportedCountry, caught in the model validator against the loaded catalog). - *legal_entity_type* must appear in that country's catalog file. - When *legal_entity_type* is ``<CC>_OTHER``, *other_label* is required (2-80 chars). - For any other type, *other_label* must be absent.
    - `country` string, required
    - `legal_entity_type` string, required
    - `other_label` string, nullable
    - `name` string, required
  - `attestation` boolean, required
  - `bot_signals` BotSignalsIn: Advisory bot-detection signals from the onboarding wizard (UC-052). Recorded and fed to scoring; never used as a hard gate.
    - `honeypot` string, nullable
    - `submit_timing_ms` integer, nullable

## Response `202`

Successful Response

- OperationOut
  - `operation_id` string, uuid, required
  - `status` string, required
  - `type` string, required
  - `target_type` string, nullable
  - `target_id` string, nullable
  - `result` unknown
  - `error` ErrorDetail
    - `code` string, required
    - `message` string, required
  - `created_at` string, date-time, required
  - `finished_at` string, date-time, nullable

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/4chems/apis/platform-api.md) · [All operations](https://skmtc.dev/4chems/apis/platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/4chems/apis/platform-api/revisions/65e4f7b4dba0?raw)
