---
title: "Self-service registration — create user, tenant, and first API key."
method: POST
path: "/v1/auth/register"
tags: ["auth"]
---

# Self-service registration — create user, tenant, and first API key.

`POST /v1/auth/register`

## Request

- Base URL: `https://api.andish.ru` (the document declares no server; this is the origin it was published from)
- URL: `https://api.andish.ru/v1/auth/register`
- Auth: none declared

Atomic registration: user + tenant + api_key in one transaction.

Returns JWT access token and the plaintext api_key (shown ONCE).
Audit-trail fields (signed_ip, signed_user_agent) come from request
headers, not from the request body.

Cross-field validation (consents, password match) is performed here
rather than in Pydantic model_validator to emit ADR-014 wire format
{"detail": {"error": "...", ...}} instead of FastAPI's default 422 shape.

## Request body

- RegisterRequest: Request body for POST /v1/auth/register. agreed_terms_v1, agreed_no_pdn and agreed_processing_metadata are required and must be True at the API layer (defence-in-depth alongside the DB CHECK constraint per ADR-018). agreed_crossborder_llm is optional since consent set consent-register-v2-2026-09-27. Audit-trail fields (signed_ip, user_agent) are populated by the endpoint from request headers — NOT sent by the client. They are modelled here for clarity of what gets persisted.
  - `email` string, email, required: User email address. Stored as CITEXT (case-insensitive unique).
  - `password` string, required: Plain-text password, hashed with argon2id before storage. Min 10 chars (OWASP 2023 baseline). No composition requirements.
  - `confirm_password` string, required: Must match password. Validated at Pydantic layer, not stored.
  - `workspace_name` string, nullable: Optional workspace display name. Defaults to the email address if not provided.
  - `agreed_terms_v1` boolean, required: User accepted Terms of Service v1. Must be True.
  - `agreed_no_pdn` boolean, required: User acknowledges they will NOT upload third-party personal data (PII) per ФЗ-152 Part В. Must be True.
  - `agreed_processing_metadata` boolean, required: User consents to processing of their content metadata per ФЗ-152 Part А. Must be True.
  - `agreed_crossborder_llm` boolean: Separate cross-border transfer flag of consent set v1. Optional since consent-register-v2-2026-09-27: defaults to false, stored as sent, not validated at registration.

## Response `201`

Successful Response

- RegisterResponse: Response for successful POST /v1/auth/register (HTTP 201). Returns the newly created user_id, tenant_id, access_token (JWT), and the plaintext api_key (shown ONCE — not stored in plaintext).
  - `user_id` string, uuid, required: Newly created user UUID.
  - `tenant_id` string, uuid, required: Newly created tenant UUID.
  - `access_token` string, required: JWT HS256 access token (TTL 12h).
  - `token_type` string: Always 'bearer'.
  - `api_key` string, required: First api_key in plaintext (adsh_test_* or adsh_live_*). Shown ONCE at registration — the server stores only the hash. Store this securely.
  - `api_key_id` string, uuid, required: UUID of the api_key record.
  - `redirect_url` string, required: Frontend URL the client should redirect to after registration. Points to the post-registration onboarding flow.

## Other responses

- `409`: Email already registered
- `422`: Validation error (missing consents, weak password, invalid email)
- `429`: Rate limit: 10 req/min per IP (middleware), or the per-day registration limit per client address / network (error=registration_limit_exceeded, with Retry-After).

---

[API](https://skmtc.dev/andish/apis/mnemo-api.md) · [All operations](https://skmtc.dev/andish/apis/mnemo-api/llms.txt) · [OpenAPI document](https://skmtc.dev/andish/apis/mnemo-api/revisions/d5449f23414c?raw)
