openapi: 3.1.0

info:
  title: Athenty API
  version: 2.0.0
  description: |
    Programmatic access to the Athenty identity verification platform.

    API access is available on **Professional, Business, and Enterprise** plans.
    Authenticate all requests with your `X-Api-Key` header.
  contact:
    name: Athenty Support
    url: https://athenty.com/contact

servers:
  - url: https://api.athenty.com/v2/api
    description: Production

security:
  - ApiKeyAuth: []

tags:
  - name: Requests
    description: Verification requests
  - name: Clients
    description: Client records

# ── Paths ────────────────────────────────────────────────────────────────────

paths:

  /requests:
    post:
      tags: [Requests]
      operationId: createRequest
      summary: Create a verification request
      description: |
        Creates a new verification request. If `subjectEmail` is provided, the
        subject receives an email invitation with a link to complete their
        verification steps.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateRequestBody'
            examples:
              idv:
                summary: Smart IDV with document and biometric
                value:
                  type: idv
                  requirements: [document, person, biometric_face]
                  subjectName: Jane Smith
                  subjectEmail: jane@example.com
                  expiresDays: 7
              kyc_linked_client:
                summary: KYC linked to existing client
                value:
                  type: kyc
                  requirements: [document, person, financial, pep_hio]
                  clientId: clt_01j9abc456
      responses:
        '201':
          description: Request created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Request'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

    get:
      tags: [Requests]
      operationId: listRequests
      summary: List verification requests
      description: Returns a paginated list of verification requests for your organization.
      parameters:
        - name: type
          in: query
          schema:
            type: string
            enum: [idv, kyc, share]
          description: Filter by verification type
        - name: status
          in: query
          schema:
            type: string
          description: |
            Filter by status. Accepts a single value or comma-separated list.
            Valid values: `initiated`, `in_progress`, `submitted`, `pending_review`,
            `approved`, `rejected`, `canceled`, `expired`
        - name: clientId
          in: query
          schema:
            type: string
            format: uuid
          description: Filter by client ID
        - name: matterId
          in: query
          schema:
            type: string
            format: uuid
          description: Filter by matter ID
        - name: search
          in: query
          schema:
            type: string
            maxLength: 100
          description: Search by subject name or email
        - name: dateFrom
          in: query
          schema:
            type: string
            format: date-time
          description: Filter requests created on or after this ISO 8601 date
        - name: dateTo
          in: query
          schema:
            type: string
            format: date-time
          description: Filter requests created on or before this ISO 8601 date
        - name: sort
          in: query
          schema:
            type: string
            enum: [created_at, updated_at, status]
          description: Sort field (default `created_at` descending)
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: Paginated list of requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedRequests'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  /requests/{id}:
    get:
      tags: [Requests]
      operationId: getRequest
      summary: Get a verification request
      description: Returns a single request with full assembled detail including step data, scores, and decisions.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Request ID
      responses:
        '200':
          description: Assembled request object
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssembledRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /clients:
    post:
      tags: [Clients]
      operationId: createClient
      summary: Create a client record
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClientBody'
            examples:
              individual:
                summary: Individual client
                value:
                  nameFirst: Jane
                  nameLast: Smith
                  email: jane@example.com
                  memberType: individual
                  country: CA
              business:
                summary: Business client
                value:
                  businessName: Acme Corp
                  email: legal@acme.com
                  memberType: business
                  country: CA
      responses:
        '201':
          description: Client created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Client'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'

    get:
      tags: [Clients]
      operationId: listClients
      summary: List clients
      parameters:
        - name: search
          in: query
          schema:
            type: string
          description: Search by name, email, or externalId
        - name: memberType
          in: query
          schema:
            type: string
            enum: [individual, business]
        - name: active
          in: query
          schema:
            type: string
            enum: ['true', 'false']
        - name: sort
          in: query
          schema:
            type: string
            enum: [name, created_at, request_count]
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: Paginated list of clients
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedClients'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  /clients/{id}:
    get:
      tags: [Clients]
      operationId: getClient
      summary: Get a client record
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Client ID
      responses:
        '200':
          description: Client record
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Client'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

# ── Components ────────────────────────────────────────────────────────────────

components:

  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: Organization API key. Available on Professional, Business, and Enterprise plans.

  schemas:

    CreateRequestBody:
      type: object
      required: [type, requirements]
      properties:
        type:
          type: string
          enum: [idv, kyc, share]
          description: Verification type
        requirements:
          type: array
          minItems: 1
          items:
            type: string
            enum: [document, person, location, contact, biometric_face, business, pep_hio, financial, consent, attestation, estate]
          description: Ordered list of verification steps to collect
        clientId:
          type: string
          format: uuid
          description: Link to an existing client record. Subject name/email/phone are loaded from the client if not overridden.
        matterId:
          type: string
          format: uuid
          description: Link to a matter
        subjectName:
          type: string
          maxLength: 128
          description: Full name of the subject being verified
        subjectEmail:
          type: string
          format: email
          description: Email address — used to send the verification invitation
        subjectPhone:
          type: string
          maxLength: 32
          description: Phone number
        expiresDays:
          type: integer
          minimum: 1
          maximum: 90
          default: 7
          description: Days until the verification link expires
        config:
          type: object
          additionalProperties: true
          description: Step-specific configuration overrides
        thirdParties:
          type: array
          items:
            $ref: '#/components/schemas/ThirdParty'
          description: Third parties to auto-share the result with on approval

    ThirdParty:
      type: object
      required: [name, email]
      properties:
        name:
          type: string
          maxLength: 128
        email:
          type: string
          format: email
        org:
          type: string
          maxLength: 128
        sharedFields:
          type: array
          items:
            type: string

    Request:
      type: object
      properties:
        id:
          type: string
        orgId:
          type: string
        type:
          type: string
          enum: [idv, kyc, share]
        status:
          type: string
          enum: [initiated, in_progress, submitted, pending_review, approved, rejected, canceled, expired]
        requirements:
          type: array
          items:
            type: string
        currentStep:
          type: string
          nullable: true
        subjectName:
          type: string
          nullable: true
        subjectEmail:
          type: string
          nullable: true
        subjectPhone:
          type: string
          nullable: true
        requestorName:
          type: string
          nullable: true
        requestorEmail:
          type: string
          nullable: true
        requestorCompany:
          type: string
          nullable: true
        clientId:
          type: string
          nullable: true
        matterId:
          type: string
          nullable: true
        expiresDays:
          type: integer
        expiresAt:
          type: string
          format: date-time
        submittedAt:
          type: string
          format: date-time
          nullable: true
        accessToken:
          type: string
          description: Token used in the subject-facing verification URL
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    AssembledRequest:
      allOf:
        - $ref: '#/components/schemas/Request'
        - type: object
          properties:
            score:
              type: number
              nullable: true
              description: Composite verification score (0–100)
            person:
              type: object
              nullable: true
              description: Identity step data
            documents:
              type: array
              description: Document step data
            biometric:
              type: object
              nullable: true
              description: Biometric step data
            location:
              type: object
              nullable: true
              description: Location step data
            contact:
              type: object
              nullable: true
              description: Contact step data
            business:
              type: object
              nullable: true
              description: Business step data
            financial:
              type: object
              nullable: true
              description: Financial step data
            pep:
              type: object
              nullable: true
              description: PEP screening results
            steps:
              type: array
              description: Step-by-step audit trail

    PaginatedRequests:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Request'
        pagination:
          $ref: '#/components/schemas/Pagination'

    CreateClientBody:
      type: object
      properties:
        nameFirst:
          type: string
          maxLength: 64
        nameLast:
          type: string
          maxLength: 64
        businessName:
          type: string
          maxLength: 128
        email:
          type: string
          format: email
          maxLength: 255
        phone:
          type: string
          maxLength: 32
        externalId:
          type: string
          maxLength: 64
          description: Your internal system identifier for this client
        memberType:
          type: string
          enum: [individual, business]
          default: individual
        addressLine1:
          type: string
          maxLength: 128
        addressLine2:
          type: string
          maxLength: 128
        city:
          type: string
          maxLength: 64
        region:
          type: string
          maxLength: 64
          description: Province or state
        postalCode:
          type: string
          maxLength: 16
        country:
          type: string
          minLength: 2
          maxLength: 2
          default: CA
          description: ISO 3166-1 alpha-2 country code
        metadata:
          type: object
          additionalProperties: true
          description: Arbitrary key-value data for your reference

    Client:
      type: object
      properties:
        id:
          type: string
        orgId:
          type: string
        nameFirst:
          type: string
          nullable: true
        nameLast:
          type: string
          nullable: true
        businessName:
          type: string
          nullable: true
        email:
          type: string
          nullable: true
        phone:
          type: string
          nullable: true
        externalId:
          type: string
          nullable: true
        memberType:
          type: string
          enum: [individual, business]
        addressLine1:
          type: string
          nullable: true
        addressLine2:
          type: string
          nullable: true
        city:
          type: string
          nullable: true
        region:
          type: string
          nullable: true
        postalCode:
          type: string
          nullable: true
        country:
          type: string
          nullable: true
        metadata:
          type: object
          nullable: true
        active:
          type: boolean
        requestCount:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    PaginatedClients:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Client'
        pagination:
          $ref: '#/components/schemas/Pagination'

    Pagination:
      type: object
      properties:
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer
        totalPages:
          type: integer
        hasNext:
          type: boolean
        hasPrev:
          type: boolean

    Error:
      type: object
      properties:
        code:
          type: string
        message:
          type: string
        statusCode:
          type: integer

    ValidationError:
      allOf:
        - $ref: '#/components/schemas/Error'
        - type: object
          properties:
            errors:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                  message:
                    type: string

  responses:

    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: UNAUTHORIZED
            message: Invalid API key.
            statusCode: 401

    PaymentRequired:
      description: Subscription inactive
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: PAYMENT_REQUIRED
            message: Your subscription is inactive. Please resubscribe to use the API.
            statusCode: 402

    Forbidden:
      description: Plan does not include API access
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: FORBIDDEN
            message: API access requires a Professional, Business, or Enterprise plan.
            statusCode: 403

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: NOT_FOUND
            message: Resource not found.
            statusCode: 404

    ValidationError:
      description: Request body failed validation
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'
          example:
            code: VALIDATION_ERROR
            message: Validation failed
            statusCode: 422
            errors:
              - field: type
                message: Required
              - field: requirements
                message: Array must contain at least 1 element(s)

    RateLimited:
      description: Too many requests
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds until the rate limit window resets
        X-RateLimit-Limit:
          schema:
            type: integer
        X-RateLimit-Remaining:
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: RATE_LIMITED
            message: Too many requests
            statusCode: 429
