openapi: 3.1.0
info:
    title: Privy Digital ID API
    version: 1.0.0
    summary: Create Digital ID verification sessions and retrieve verified results.
    description: |
        Privy Digital ID is an identity verification service that merchants embed
        in an iframe or a native WebView. The merchant creates a session from its
        backend and receives verified data as a Privy-signed JWT.

        The merchant API key and all verified data must remain on the merchant
        backend. The widget handles identity input, liveness, face matching,
        OTP, and consent.
servers:
    - url: https://stg-api-digitalid.privy.id
      description: Sandbox
    - url: https://api-digitalid.privy.id
      description: Production
tags:
    - name: Sessions
      description: Create a verification session and exchange its result code.
    - name: Service
      description: Public verification-key and health endpoints.
paths:
    /v1/sessions:
        post:
            operationId: createVerificationSession
            summary: Create a verification session
            description: |
                Creates a verification session and returns the widget URL to embed.
                This request has no body. Privy configures the data package (Contact
                or Identity), its data items, and the widget settings for each
                merchant at onboarding.

                If the request times out, create a new session. The unused session
                expires automatically and is not charged.
            tags:
                - Sessions
            security:
                - apiKeyAuth: []
            responses:
                "201":
                    description: Verification session created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/Session"
                            examples:
                                created:
                                    value:
                                        session_id: 9f1c2c8a-2d6f-4d60-9ab1-85a5d4aa93d0
                                        session_url: https://stg-digitalid.privy.id/?t=eyJ...
                                        expires_at: "2026-07-21T18:15:00Z"
                "400":
                    $ref: "#/components/responses/InvalidInput"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
                "409":
                    $ref: "#/components/responses/InvalidState"
                "410":
                    $ref: "#/components/responses/SessionExpired"
                "423":
                    $ref: "#/components/responses/SessionBlocked"
                "429":
                    $ref: "#/components/responses/RateLimited"
    /v1/sessions/exchange:
        post:
            operationId: exchangeVerificationCode
            summary: Exchange a verification code
            description: |
                Exchanges the single-use code from the `privy:success` event for a
                verified-data JWT. The code has a short lifetime of approximately five
                minutes and requires the merchant API key.

                This endpoint does not return the session status, and it does not
                accept `session_id`. An expired or reused code returns `404 not_found`
                or `410 session_expired`.
            tags:
                - Sessions
            security:
                - apiKeyAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ExchangeRequest"
                        examples:
                            resultCode:
                                value:
                                    code: exchange-code-from-privy-success
            responses:
                "200":
                    description: Code exchanged for a verified-data token
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ExchangeResult"
                            examples:
                                verified:
                                    value:
                                        session_id: 9f1c2c8a-2d6f-4d60-9ab1-85a5d4aa93d0
                                        event: identity.verified
                                        token: eyJ...verified-data-jwt
                "400":
                    $ref: "#/components/responses/InvalidInput"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
                "409":
                    $ref: "#/components/responses/InvalidState"
                "410":
                    $ref: "#/components/responses/SessionExpired"
                "423":
                    $ref: "#/components/responses/SessionBlocked"
                "429":
                    $ref: "#/components/responses/RateLimited"
    /.well-known/jwks.json:
        get:
            operationId: getJsonWebKeySet
            summary: Get the JSON Web Key Set
            description: |
                Returns the public Ed25519 keys that verify Digital ID tokens. The
                response follows RFC 7517. Select the key that matches the JWT `kid`
                header on each verification. A key-rotation schedule is not published.
            tags:
                - Service
            security: []
            responses:
                "200":
                    description: JSON Web Key Set
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/JsonWebKeySet"
                            examples:
                                ed25519:
                                    value:
                                        keys:
                                            - kty: OKP
                                              crv: Ed25519
                                              alg: EdDSA
                                              use: sig
                                              kid: digital-id-key-1
                                              x: base64url-public-key
    /healthz:
        get:
            operationId: getServiceHealth
            summary: Get service health
            description: Returns HTTP 200 when the Digital ID service is healthy. No response body is defined.
            tags:
                - Service
            security: []
            responses:
                "200":
                    description: Service is healthy
components:
    securitySchemes:
        apiKeyAuth:
            type: apiKey
            in: header
            name: X-API-Key
            description: Merchant API key. Send this header only from the merchant backend.
    schemas:
        Session:
            type: object
            additionalProperties: false
            required:
                - session_id
                - session_url
                - expires_at
            properties:
                session_id:
                    type: string
                    description: Unique verification-session identifier.
                session_url:
                    type: string
                    format: uri
                    description: Widget URL to load in an iframe or WebView.
                expires_at:
                    type: string
                    format: date-time
                    description: Time at which the session expires. Use this value. A fixed session duration is not guaranteed.
        ExchangeRequest:
            type: object
            additionalProperties: false
            required:
                - code
            properties:
                code:
                    type: string
                    minLength: 1
                    description: Single-use code from `privy:success.payload.exchange_code`.
        ExchangeResult:
            type: object
            additionalProperties: false
            required:
                - session_id
                - event
                - token
            properties:
                session_id:
                    type: string
                event:
                    type: string
                    const: identity.verified
                token:
                    type: string
                    description: Privy-signed EdDSA verified-data JWT.
        JsonWebKeySet:
            type: object
            additionalProperties: false
            required:
                - keys
            properties:
                keys:
                    type: array
                    items:
                        $ref: "#/components/schemas/Ed25519JsonWebKey"
        Ed25519JsonWebKey:
            type: object
            additionalProperties: false
            required:
                - kty
                - crv
                - alg
                - use
                - kid
                - x
            properties:
                kty:
                    type: string
                    const: OKP
                crv:
                    type: string
                    const: Ed25519
                alg:
                    type: string
                    const: EdDSA
                use:
                    type: string
                    const: sig
                kid:
                    type: string
                    description: Key identifier from the JWT header.
                x:
                    type: string
                    description: Base64url-encoded Ed25519 public key.
        Error:
            type: object
            additionalProperties: false
            required:
                - error
            properties:
                error:
                    type: object
                    additionalProperties: false
                    required:
                        - code
                        - message
                    properties:
                        code:
                            type: string
                            description: Machine-readable error code, for example `invalid_input`.
                        message:
                            type: string
                            description: Human-readable description. Do not parse this value. Use `error.code` instead.
    responses:
        InvalidInput:
            description: The request body or a parameter is invalid.
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/Error"
                    example:
                        error:
                            code: invalid_input
                            message: The request input is invalid.
        Unauthorized:
            description: The API key or token is invalid.
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/Error"
                    example:
                        error:
                            code: unauthorized
                            message: The request is not authorized.
        NotFound:
            description: The session, merchant, or exchange code was not found.
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/Error"
                    example:
                        error:
                            code: not_found
                            message: The requested resource was not found.
        InvalidState:
            description: The requested action is not allowed at the current step.
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/Error"
                    example:
                        error:
                            code: invalid_state
                            message: The session is not in the required state.
        SessionExpired:
            description: The verification session has expired, including when the consent confirmation window ends.
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/Error"
                    example:
                        error:
                            code: session_expired
                            message: The verification session has expired.
        SessionBlocked:
            description: The session is blocked after three failed liveness or face-match attempts.
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/Error"
                    example:
                        error:
                            code: session_blocked
                            message: The verification session is blocked.
        RateLimited:
            description: The client sent too many requests. Reduce the request rate before you retry.
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/Error"
                    example:
                        error:
                            code: rate_limited
                            message: Too many requests.
