## Registrations (`registrations`)

No authentication needed. Submits registration details to create a tenant account; the agreement must be accepted and verified email or phone needs a code.

Authentication: No auth · Docs: https://www-demo.kuxitong.com/en/docs/api/registrations

### POST `/api/v2/registrations`

Register · Authentication: No auth

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `accept_agreement` | boolean | Yes | Must be true |
| `email` | string |  | Email |
| `email_code` | string |  | Code sent to the email (POST /verify-codes, purpose=bind); required when the email must be verified |
| `password` | string | Yes | Login password, 8 to 128 characters |
| `phone` | string |  | Phone number |
| `phone_code` | string |  | Code sent to the phone number (POST /verify-codes, purpose=bind); required when the phone number must be verified |
| `username` | string |  | Required if registration info demands it, otherwise generated automatically. Must not look like a phone number (all digits) |

```sh
curl -X POST "https://panel.example.com/api/v2/registrations" \
  -H "Content-Type: application/json" \
  -d '{"accept_agreement":true,"email":"alice@example.com","email_code":"123456","password":"${PASSWORD}","username":"alice"}'
```

Registrations object:

| Field | Type | Required | Description |
|---|---|---|---|
| `accept_agreement` | boolean | Yes | Must be true |
| `balance_cents` | integer |  | Account balance in cents, same as balance_cents of GET /users/{user_id}/account (0 when there is no account). Only present in the GET /users list, not in single-user responses (read-only) |
| `certified` | boolean |  | Whether real-name verification has passed |
| `client_ip` | string |  | Source IP of this request, derived the same way as the login IP allowlist check (what the allowlist compares is what is shown). Only present in GET /me and PUT /me (read-only) |
| `created_at` | string |  | Created at (read-only) |
| `delegated_session` | boolean |  | Whether the current session was issued by superadmin sign-in or switch-to-user (if so, password, email, phone, login allowlist, login verification and real-name are read-only). Only present in GET /me and PUT /me (read-only) |
| `email` | string |  | Email |
| `email_code` | string |  | Code sent to the email (POST /verify-codes, purpose=bind); required when the email must be verified |
| `enabled` | boolean |  | Whether enabled |
| `id` | integer |  | Record ID (read-only) |
| `login_ip_allow` | string[] |  | Login IP allowlist (IPs or CIDRs); empty means no restriction |
| `login_verify` | LoginVerify |  | Second-factor login: none means not required; email / sms also require an email/SMS code at login (the platform must allow it and the address must be bound) Values: ["none","email","sms"] |
| `password` | string | Yes | Login password, 8 to 128 characters |
| `phone` | string |  | Phone number |
| `phone_code` | string |  | Code sent to the phone number (POST /verify-codes, purpose=bind); required when the phone number must be verified |
| `role` | string |  | Account role: admin or tenant Values: ["admin","tenant"] |
| `totp_enabled` | boolean |  | Whether TOTP is enabled |
| `totp_recovery_left` | integer |  | Number of unused TOTP recovery codes. Only present in GET /me and PUT /me when TOTP is enabled (read-only) |
| `updated_at` | string |  | Updated at (read-only) |
| `username` | string |  | Required if registration info demands it, otherwise generated automatically. Must not look like a phone number (all digits) |
