> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tai42.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Initialize the deployment (owner + first key)

> Initialize the deployment once behind the secure-by-default setup-token gate.

Only meaningful on a serviceable access-controlled install: it refuses loudly with a
501 when the door cannot initialize — access control off, no configured key-minting
identity provider, or the access-control Redis unset. The per-IP backoff is consulted
BEFORE the token, so a wrong-token flood escalates a lockout that turns further attempts away
without ever comparing; a wrong/absent token is a generic 403 (no oracle for the
initialized state). Under one mint mutex: 409 "Already initialized" when ANY principal
exists; else the owner principal (``kind=human``) is created, granted the admin role,
its first key (owned by the owner) is minted and returned ONCE, and — when a configured
accounts provider can attach a login and the request carries one — the owner's login is
attached (a password set now, or an invite whose one-time link is returned). A failure
past the owner create is compensated so setup stays retriable; a correctable login
credential is compensated then mapped to the caller (a too-short password → 400, a
login/email collision → 409) rather than surfaced as a 500.



## OpenAPI

````yaml /openapi.json post /api/setup
openapi: 3.1.0
info:
  description: The operator HTTP surface served under /api/*.
  title: tai42-skeleton API
  version: 18.0.1
servers: []
security: []
paths:
  /api/setup:
    post:
      tags:
        - access-control
      summary: Initialize the deployment (owner + first key)
      description: >-
        Initialize the deployment once behind the secure-by-default setup-token
        gate.


        Only meaningful on a serviceable access-controlled install: it refuses
        loudly with a

        501 when the door cannot initialize — access control off, no configured
        key-minting

        identity provider, or the access-control Redis unset. The per-IP backoff
        is consulted

        BEFORE the token, so a wrong-token flood escalates a lockout that turns
        further attempts away

        without ever comparing; a wrong/absent token is a generic 403 (no oracle
        for the

        initialized state). Under one mint mutex: 409 "Already initialized" when
        ANY principal

        exists; else the owner principal (``kind=human``) is created, granted
        the admin role,

        its first key (owned by the owner) is minted and returned ONCE, and —
        when a configured

        accounts provider can attach a login and the request carries one — the
        owner's login is

        attached (a password set now, or an invite whose one-time link is
        returned). A failure

        past the owner create is compensated so setup stays retriable; a
        correctable login

        credential is compensated then mapped to the caller (a too-short
        password → 400, a

        login/email collision → 409) rather than surfaced as a 500.
      operationId: post_api_setup
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetupRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  data:
                    $ref: '#/components/schemas/SetupResult'
                required:
                  - data
                type: object
          description: Success.
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Malformed request.
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Forbidden.
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Conflict with the current resource state.
        '501':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Error.
components:
  schemas:
    SetupRequest:
      additionalProperties: false
      description: >-
        The body of ``POST /api/setup``.


        ``setup_token`` is checked against the deployment's setup token.

        ``owner_user_id`` and ``key_user_id`` are optional — the door mints ids
        when

        they are absent. ``owner_display_name`` is required and non-empty (the

        principals door rejects an empty display name). ``login`` attaches the
        owner's

        interactive login when a login-attaching provider is configured; a
        keys-only

        deployment sends ``None``.
      properties:
        key_description:
          default: owner key
          title: Key Description
          type: string
        key_user_id:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Key User Id
        login:
          anyOf:
            - discriminator:
                mapping:
                  invite:
                    $ref: '#/components/schemas/InviteCredential'
                  password:
                    $ref: '#/components/schemas/PasswordCredential'
                propertyName: kind
              oneOf:
                - $ref: '#/components/schemas/PasswordCredential'
                - $ref: '#/components/schemas/InviteCredential'
            - type: 'null'
          default: null
          title: Login
        owner_display_name:
          minLength: 1
          title: Owner Display Name
          type: string
        owner_user_id:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Owner User Id
        setup_token:
          default: ''
          title: Setup Token
          type: string
      required:
        - owner_display_name
      title: SetupRequest
      type: object
    SetupResult:
      additionalProperties: false
      description: >-
        The result of a successful ``POST /api/setup``.


        ``api_key`` is the owner key's plaintext, returned exactly once.

        ``login_attached`` is whether an interactive login was attached;

        ``invite_token`` and ``login_path`` are set only when the login was an
        invite

        the operator completes later.
      properties:
        api_key:
          title: Api Key
          type: string
        invite_token:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Invite Token
        key_fingerprint:
          title: Key Fingerprint
          type: string
        key_user_id:
          title: Key User Id
          type: string
        login_attached:
          title: Login Attached
          type: boolean
        login_path:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Login Path
        owner_user_id:
          title: Owner User Id
          type: string
      required:
        - owner_user_id
        - key_user_id
        - api_key
        - key_fingerprint
        - login_attached
      title: SetupResult
      type: object
    Error:
      properties:
        code:
          description: >-
            Stable machine-readable reason a client keys a dedicated error state
            on, present on refusals that opt in (e.g. a 501 not-configured
            refusal). Optional: absent when the error carries only a
            human-readable message.
          type: string
        error:
          type: string
      required:
        - error
      type: object
    InviteCredential:
      additionalProperties: false
      description: >-
        A login credential that mints a one-time invite link instead of setting
        a password now.
      properties:
        email:
          minLength: 1
          title: Email
          type: string
        kind:
          const: invite
          default: invite
          title: Kind
          type: string
      required:
        - email
      title: InviteCredential
      type: object
    PasswordCredential:
      additionalProperties: false
      description: A login credential that sets the principal's password now.
      properties:
        email:
          minLength: 1
          title: Email
          type: string
        kind:
          const: password
          default: password
          title: Kind
          type: string
        password:
          minLength: 1
          title: Password
          type: string
      required:
        - email
        - password
      title: PasswordCredential
      type: object

````