openapi: 3.0.3
info:
  title: Kaito Users API
  version: 2.0.0
  description: >
    User management: Identity verification, Wallets, and Directory services.


    **Identity (KYC/KYB):** KYC for individual verification, KYB for company
    verification.


    **Wallets:** Custodial wallet management with key material. Supports
    Ethereum, Polygon, Solana, Bitcoin.


    **Directory:** Resolve handles, phones, addresses to destinations. Register
    handles and manage contact books.
  termsOfService: https://developer.kai2.io/terms
  contact:
    name: Kaito Developer Support
    url: https://developer.kai2.io/support
    email: support@kai2.io
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0
servers:
  - url: https://api.kai2.io
    description: Production
  - url: https://sandbox.api.kai2.io
    description: Sandbox
x-tagGroups:
  - name: Identity
    tags:
      - Identity
  - name: Wallets
    tags:
      - Wallets
  - name: Directory
    tags:
      - Resolution
      - Handles
      - Contacts
tags:
  - name: Identity
    description: KYC/KYB verification
  - name: Wallets
    description: Custodial wallet management
  - name: Resolution
    description: Resolve identifiers to destinations
  - name: Handles
    description: Manage handle registrations
  - name: Contacts
    description: Manage contact book
paths:
  /v1/identity/verify:
    post:
      summary: Submit KYC/KYB verification
      tags:
        - Identity
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerificationCreateRequest'
      responses:
        '202':
          description: Verification submitted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Verification'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/identity/verifications:
    get:
      summary: List verifications
      tags:
        - Identity
      parameters:
        - in: query
          name: status
          schema:
            $ref: '#/components/schemas/VerificationStatus'
        - in: query
          name: type
          schema:
            $ref: '#/components/schemas/VerificationType'
        - in: query
          name: limit
          schema:
            type: integer
            default: 50
        - in: query
          name: cursor
          schema:
            type: string
      responses:
        '200':
          description: Verifications list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Verification'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
  /v1/identity/verifications/{verificationId}:
    get:
      summary: Get verification status
      tags:
        - Identity
      parameters:
        - name: verificationId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Verification details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Verification'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/wallets:
    post:
      summary: Create custodial wallet
      tags:
        - Wallets
      description: Creates a wallet and returns key material. Store secrets securely.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WalletCreateRequest'
      responses:
        '201':
          description: Wallet created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletCreateResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
    get:
      summary: List wallets
      tags:
        - Wallets
      parameters:
        - in: query
          name: ownerRef
          schema:
            type: string
        - in: query
          name: network
          schema:
            $ref: '#/components/schemas/Network'
        - in: query
          name: limit
          schema:
            type: integer
            default: 50
        - in: query
          name: cursor
          schema:
            type: string
      responses:
        '200':
          description: Wallets list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Wallet'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
  /v1/wallets/{walletId}:
    get:
      summary: Get wallet by ID
      tags:
        - Wallets
      parameters:
        - name: walletId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Wallet details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Wallet'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/wallets/{walletId}/balances:
    get:
      summary: Get wallet balances
      tags:
        - Wallets
      parameters:
        - name: walletId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Wallet balances
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletBalancesResponse'
  /v1/directory/resolve:
    post:
      summary: Resolve handle/phone/address to destination
      tags:
        - Resolution
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResolveRequest'
      responses:
        '200':
          description: Successfully resolved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResolveResponse'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/directory/handles:
    post:
      summary: Register handle
      tags:
        - Handles
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HandleCreateRequest'
      responses:
        '201':
          description: Handle registered
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Handle'
        '409':
          description: Conflict - Handle already exists
    get:
      summary: List handles
      tags:
        - Handles
      parameters:
        - in: query
          name: limit
          schema:
            type: integer
            default: 50
        - in: query
          name: cursor
          schema:
            type: string
      responses:
        '200':
          description: Handles list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Handle'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
  /v1/directory/handles/{handle}:
    get:
      summary: Get handle
      tags:
        - Handles
      parameters:
        - name: handle
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Handle details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Handle'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      summary: Delete handle
      tags:
        - Handles
      parameters:
        - name: handle
          in: path
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Handle deleted
  /v1/directory/contacts:
    post:
      summary: Create contact
      tags:
        - Contacts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactCreateRequest'
      responses:
        '201':
          description: Contact created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact'
    get:
      summary: List contacts
      tags:
        - Contacts
      parameters:
        - in: query
          name: ownerRef
          required: true
          schema:
            type: string
        - in: query
          name: limit
          schema:
            type: integer
            default: 50
        - in: query
          name: cursor
          schema:
            type: string
      responses:
        '200':
          description: Contacts list
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Contact'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
  /v1/directory/contacts/{contactId}:
    delete:
      summary: Delete contact
      tags:
        - Contacts
      parameters:
        - name: contactId
          in: path
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Contact deleted
components:
  securitySchemes:
    oAuth2:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://auth.kai2.io/oauth2/token
          scopes:
            identity:write: Run KYC/KYB
            identity:read: Read verifications
            wallets:write: Create wallets
            wallets:read: Read wallets
            directory:write: Register handles
            directory:read: Resolve identifiers
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
  responses:
    BadRequest:
      description: Bad Request
    Unauthorized:
      description: Access token is missing or invalid.
    NotFound:
      description: The requested resource does not exist.
  schemas:
    TraceId:
      type: string
      example: trc_01JH8K5P3V9M2K5Q7W6J3Z1A9B
    Pagination:
      type: object
      properties:
        nextCursor:
          type: string
          nullable: true
    Network:
      type: string
      enum:
        - ethereum
        - polygon
        - solana
        - bitcoin
    VerificationType:
      type: string
      enum:
        - KYC
        - KYB
    VerificationStatus:
      type: string
      enum:
        - pending
        - in_review
        - approved
        - rejected
        - expired
    DocumentType:
      type: string
      enum:
        - passport
        - national_id
        - drivers_license
        - utility_bill
        - bank_statement
        - incorporation_certificate
        - tax_id
    Subject:
      type: object
      properties:
        firstName:
          type: string
        lastName:
          type: string
        dob:
          type: string
          format: date
        nationalId:
          type: string
        country:
          type: string
        email:
          type: string
          format: email
        phone:
          type: string
        businessName:
          type: string
        registrationNumber:
          type: string
        businessType:
          type: string
          enum:
            - corporation
            - llc
            - partnership
            - sole_proprietorship
            - nonprofit
    Document:
      type: object
      required:
        - type
        - file
      properties:
        type:
          $ref: '#/components/schemas/DocumentType'
        file:
          type: string
          format: byte
        side:
          type: string
          enum:
            - front
            - back
    VerificationCreateRequest:
      type: object
      required:
        - type
        - subject
      properties:
        type:
          $ref: '#/components/schemas/VerificationType'
        subject:
          $ref: '#/components/schemas/Subject'
        documents:
          type: array
          items:
            $ref: '#/components/schemas/Document'
        callbackUrl:
          type: string
          format: uri
    Verification:
      type: object
      required:
        - verificationId
        - type
        - status
        - createdAt
      properties:
        verificationId:
          type: string
          example: ver_01JH...
        type:
          $ref: '#/components/schemas/VerificationType'
        status:
          $ref: '#/components/schemas/VerificationStatus'
        subject:
          $ref: '#/components/schemas/Subject'
        reason:
          type: string
        riskScore:
          type: number
        createdAt:
          type: string
          format: date-time
        expiresAt:
          type: string
          format: date-time
    WalletCreateRequest:
      type: object
      required:
        - ownerRef
        - network
      properties:
        ownerRef:
          type: string
          example: usr_12345
        network:
          $ref: '#/components/schemas/Network'
        custodyModel:
          type: string
          enum:
            - custodial
          default: custodial
    WalletSecrets:
      type: object
      properties:
        address:
          type: string
        privateKey:
          type: string
        mnemonic:
          type: string
    Wallet:
      type: object
      required:
        - walletId
        - network
        - address
        - createdAt
      properties:
        walletId:
          type: string
          example: wlt_01JH...
        address:
          type: string
        network:
          $ref: '#/components/schemas/Network'
        custodyModel:
          type: string
          enum:
            - custodial
        createdAt:
          type: string
          format: date-time
    WalletCreateResponse:
      type: object
      required:
        - wallet
        - secrets
      properties:
        wallet:
          $ref: '#/components/schemas/Wallet'
        secrets:
          $ref: '#/components/schemas/WalletSecrets'
    BalanceItem:
      type: object
      properties:
        asset:
          type: string
          example: USDT
        network:
          $ref: '#/components/schemas/Network'
        amount:
          type: string
          example: '125.50'
        decimals:
          type: integer
    WalletBalancesResponse:
      type: object
      properties:
        walletId:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/BalanceItem'
    ResolveRequest:
      type: object
      required:
        - input
      properties:
        input:
          type: string
          example: '+50255551234'
        networkHint:
          $ref: '#/components/schemas/Network'
    ResolveResponse:
      type: object
      required:
        - displayName
        - address
        - network
        - resolvedBy
      properties:
        displayName:
          type: string
        address:
          type: string
        network:
          $ref: '#/components/schemas/Network'
        resolvedBy:
          type: string
          enum:
            - handle
            - phone
            - address
            - qr
    HandleCreateRequest:
      type: object
      required:
        - handle
        - address
        - network
      properties:
        handle:
          type: string
          example: '@recipient'
        address:
          type: string
        network:
          $ref: '#/components/schemas/Network'
        displayName:
          type: string
    Handle:
      type: object
      properties:
        handle:
          type: string
        address:
          type: string
        network:
          $ref: '#/components/schemas/Network'
        displayName:
          type: string
        createdAt:
          type: string
          format: date-time
    ContactCreateRequest:
      type: object
      required:
        - ownerRef
        - name
        - destination
      properties:
        ownerRef:
          type: string
        name:
          type: string
        destination:
          type: string
    Contact:
      type: object
      properties:
        contactId:
          type: string
        ownerRef:
          type: string
        name:
          type: string
        destination:
          type: string
        createdAt:
          type: string
          format: date-time
security:
  - oAuth2: []
