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

# Add a signer to a customer's wallets

> Adds a new signer to the customer's wallet infrastructure. An add to a live (already-active) roster typically needs one admin approval — see [Multi-signer wallets](/concepts/multi-signer-wallets). The synchronous response returns a `verificationUrl` whose audience is given by `urlAudience`: a passkey signer gets their own enrollment link (`urlAudience: "signer"`, also delivered via the `wallet_signer.invited` webhook) — deliver it to the signer. For a passkey signer added to a live roster this `"signer"` link is the FIRST of two steps, not full self-service: once the signer enrolls their passkey the add parks a roster-add ceremony for a customer admin's co-stamp, and that admin link arrives ONLY on the `wallet_ceremony.awaiting_admin_approval` webhook (carrying the ceremony's `ceremonyId`), never in this response. An api_key signer that parks for admin approval instead returns the admin co-stamp link inline (`urlAudience: "admin"`, also delivered via the `wallet_ceremony.awaiting_admin_approval` webhook) — deliver it to an admin; a synchronously-admitted api_key signer returns null/null. A parked api_key add whose activity is still resolving at the custody provider ALSO returns null/null, but with `awaitingProvider: true` set — that flag is what distinguishes "nothing to do, fully admitted" from "nothing to do yet, still resolving" until the admin link becomes available (poll `reissue-admin-approval`, which mints it once the provider settles). If the admin webhook is lost, recover the admin link with `POST /wallet-signers/{signerId}/reissue-admin-approval`. When an api_key add parks on a roster that carries an ACTIVE api_key admin, the response ADDS `machineApproval` (a token + `approvalMaterial`) alongside that admin link and webhook: stamp the material with an ACTIVE api_key admin key and POST `{ method: "api_key", credential }` to `/v2/verifications/{token}/complete` (credential is a JSON string of `{ signedBody, stamp, organizationId }`) to activate the signer without opening the link — the same stamp-and-approve step every machine governance ceremony uses. Conduit never emails anyone — your platform delivers the link. Route by `urlAudience`, never assume the URL is the signer's.

The same signing-mode roster rules as the claim apply to later adds: api_key signers are only valid under a programmatic signing mode, and api_key admins only under programmatic unattended — otherwise `422 SIGNING_MODE_ROSTER_INVALID`. An api_key signer must include `publicKey` (compressed P-256: 33 bytes / 66 hex chars, `02`/`03` prefix); a key already on an active signer returns `409 API_KEY_PUBLIC_KEY_IN_USE`. See [Programmatic payout signing](/guides/machine-signer-stamping).



## OpenAPI

````yaml https://api.sandbox.conduit.financial/v2/api-docs/openapi.json post /customers/{customerId}/wallet-signers
openapi: 3.0.0
info:
  title: Conduit Sandbox API
  description: >-
    **Sandbox API** — clients integrate against this surface to exercise happy
    and unhappy paths without consuming real KYC/PSP credits or moving real
    money. Customer KYC, banking partners, and crypto custody are stubbed;
    org-level KYB runs against real providers. Simulation endpoints under
    `/v2/sandbox/*` drive specific scenarios.


    Internal and portal endpoints are excluded from this spec.
  version: '2.0'
  contact: {}
servers:
  - url: https://api.sandbox.conduit.financial/v2
    description: Sandbox
  - url: https://api.conduit.financial/v2
    description: Production
security:
  - api-key: []
tags:
  - name: Customers
  - name: Registered Addresses
  - name: Wallets
  - name: Wallet Signers
  - name: Signing Quorum
  - name: Virtual Accounts
  - name: Applications
  - name: Documents
  - name: Verifications
  - name: Signing Requests
  - name: Transactions
  - name: Payouts
  - name: Whitelist Recipients
  - name: Orders
  - name: Quotes
  - name: RFIs
  - name: Webhook Endpoints
  - name: Webhook Deliveries
  - name: Webhook Event Types
  - name: Features
  - name: Customer Onboarding
  - name: Markup
  - name: Sandbox
paths:
  /customers/{customerId}/wallet-signers:
    post:
      tags:
        - Wallet Signers
      summary: Add a signer to a customer's wallets
      description: >-
        Adds a new signer to the customer's wallet infrastructure. An add to a
        live (already-active) roster typically needs one admin approval — see
        [Multi-signer wallets](/concepts/multi-signer-wallets). The synchronous
        response returns a `verificationUrl` whose audience is given by
        `urlAudience`: a passkey signer gets their own enrollment link
        (`urlAudience: "signer"`, also delivered via the `wallet_signer.invited`
        webhook) — deliver it to the signer. For a passkey signer added to a
        live roster this `"signer"` link is the FIRST of two steps, not full
        self-service: once the signer enrolls their passkey the add parks a
        roster-add ceremony for a customer admin's co-stamp, and that admin link
        arrives ONLY on the `wallet_ceremony.awaiting_admin_approval` webhook
        (carrying the ceremony's `ceremonyId`), never in this response. An
        api_key signer that parks for admin approval instead returns the admin
        co-stamp link inline (`urlAudience: "admin"`, also delivered via the
        `wallet_ceremony.awaiting_admin_approval` webhook) — deliver it to an
        admin; a synchronously-admitted api_key signer returns null/null. A
        parked api_key add whose activity is still resolving at the custody
        provider ALSO returns null/null, but with `awaitingProvider: true` set —
        that flag is what distinguishes "nothing to do, fully admitted" from
        "nothing to do yet, still resolving" until the admin link becomes
        available (poll `reissue-admin-approval`, which mints it once the
        provider settles). If the admin webhook is lost, recover the admin link
        with `POST /wallet-signers/{signerId}/reissue-admin-approval`. When an
        api_key add parks on a roster that carries an ACTIVE api_key admin, the
        response ADDS `machineApproval` (a token + `approvalMaterial`) alongside
        that admin link and webhook: stamp the material with an ACTIVE api_key
        admin key and POST `{ method: "api_key", credential }` to
        `/v2/verifications/{token}/complete` (credential is a JSON string of `{
        signedBody, stamp, organizationId }`) to activate the signer without
        opening the link — the same stamp-and-approve step every machine
        governance ceremony uses. Conduit never emails anyone — your platform
        delivers the link. Route by `urlAudience`, never assume the URL is the
        signer's.


        The same signing-mode roster rules as the claim apply to later adds:
        api_key signers are only valid under a programmatic signing mode, and
        api_key admins only under programmatic unattended — otherwise `422
        SIGNING_MODE_ROSTER_INVALID`. An api_key signer must include `publicKey`
        (compressed P-256: 33 bytes / 66 hex chars, `02`/`03` prefix); a key
        already on an active signer returns `409 API_KEY_PUBLIC_KEY_IN_USE`. See
        [Programmatic payout signing](/guides/machine-signer-stamping).
      operationId: WalletSignersController_addSigner_v2
      parameters:
        - name: customerId
          required: true
          in: path
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          description: >-
            Caller-generated unique key that lets the server safely replay this
            request. The cached response is returned for 5 minutes on any retry
            with the same key from the same API principal. Required on every
            state-changing money-moving or resource-creating POST.
          required: true
          schema:
            type: string
            pattern: ^[A-Za-z0-9_.:-]{1,128}$
            minLength: 1
            maxLength: 128
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddWalletSignerDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AddWalletSignerResponseDto'
        '400':
          description: >-
            **INVALID_OID_FORMAT**: A path or query parameter expected a valid
            object identifier but received a value that does not match the
            expected format.


            **VALIDATION_ERROR**: The request body or query parameters failed
            validation. One or more fields have invalid values, missing required
            properties, or incorrect types. Multipart file uploads that fail at
            the multipart-parser layer (unexpected form-field name, too many
            parts) carry an extra 'field' member naming the offending
            form-field.


            **MALFORMED_JSON**: The request body could not be parsed as JSON.
            Bodies declared as 'application/json' — and bodies with no
            Content-Type header, which are assumed to be JSON — must contain
            syntactically valid JSON.


            **IDEMPOTENCY_KEY_REQUIRED**: This endpoint requires an
            Idempotency-Key header to prevent duplicate processing. Generate a
            unique key per logical request and resend the request.


            **IDEMPOTENCY_KEY_INVALID**: The Idempotency-Key header value did
            not match the required shape (1-128 characters, letters / digits /
            underscore / dot / colon / hyphen).


            **IDEMPOTENCY_BODY_TOO_NESTED**: The request body exceeds the
            maximum nesting depth allowed by the idempotency fingerprint hasher.
            Deeply-nested arrays or objects are rejected as a malformed payload.


            **API_KEY_PUBLIC_KEY_REQUIRED**: credentialType=api_key requires a
            publicKey (a P-256 compressed public key in hex).


            **API_KEY_PUBLIC_KEY_INVALID**: The provided `publicKey` is not a
            valid P-256 compressed public key. Expected 66 hex characters (33
            bytes) with a `02` or `03` prefix.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorDto'
              example:
                type: INVALID_OID_FORMAT
                title: Invalid Object ID Format
                status: 400
                detail: >-
                  A path or query parameter expected a valid object identifier
                  but received a value that does not match the expected format.
                resolution: >-
                  Verify that all IDs in the request URL and query parameters
                  are correctly formatted. IDs are typically prefixed strings
                  like 'cus_...', 'app_...', or 'doc_...'.
                docs: https://conduit-v2.mintlify.app/errors#invalid-oid-format
                instance: /v2/...
                correlationId: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
                timestamp: '2026-01-15T09:30:00.000Z'
        '401':
          description: >-
            **API_KEY_MISSING**: The request did not include an API key. All API
            requests must be authenticated.


            **API_KEY_INVALID**: The provided API key is not recognized or has
            been revoked.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetailDto'
              example:
                type: API_KEY_MISSING
                title: API Key Missing
                status: 401
                detail: >-
                  The request did not include an API key. All API requests must
                  be authenticated.
                resolution: >-
                  Include your API key in the 'x-api-key' header with every
                  request.
                docs: https://conduit-v2.mintlify.app/errors#api-key-missing
                instance: /v2/...
                correlationId: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
                timestamp: '2026-01-15T09:30:00.000Z'
        '403':
          description: >-
            **API_KEY_READ_ONLY**: This API key has read-only access and cannot
            perform write operations. Read-only keys may make read requests
            (GET, HEAD, OPTIONS) only.


            **FEATURE_NOT_ENABLED**: Your account does not have access to this
            feature. Features are enabled on a per-account basis.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetailDto'
              example:
                type: API_KEY_READ_ONLY
                title: API Key Is Read-Only
                status: 403
                detail: >-
                  This API key has read-only access and cannot perform write
                  operations. Read-only keys may make read requests (GET, HEAD,
                  OPTIONS) only.
                resolution: >-
                  Use a read-write API key for this request, or have an
                  organization admin mint one from the dashboard.
                docs: https://conduit-v2.mintlify.app/errors#api-key-read-only
                instance: /v2/...
                correlationId: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
                timestamp: '2026-01-15T09:30:00.000Z'
        '404':
          description: >-
            **CUSTOMER_NOT_FOUND**: No customer exists with the specified ID, or
            the customer belongs to a different organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetailDto'
              example:
                type: CUSTOMER_NOT_FOUND
                title: Customer Not Found
                status: 404
                detail: >-
                  No customer exists with the specified ID, or the customer
                  belongs to a different organization.
                resolution: >-
                  Verify the customer ID is correct. Use the list customers
                  endpoint to find valid customer IDs for your organization.
                docs: https://conduit-v2.mintlify.app/errors#customer-not-found
                instance: /v2/...
                correlationId: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
                timestamp: '2026-01-15T09:30:00.000Z'
        '409':
          description: >-
            **IDEMPOTENCY_KEY_CONFLICT**: The idempotency key was previously
            used with a different request body. Idempotency keys are bound to
            the exact request shape — replays must match the original.


            **IDEMPOTENCY_KEY_REQUEST_IN_PROGRESS**: A request with this
            idempotency key is already being processed and has not yet
            completed. Concurrent requests with the same key are rejected to
            prevent duplicate execution.


            **API_KEY_PUBLIC_KEY_IN_USE**: The `publicKey` on this add-signer
            request is already held by another active api_key signer on the
            customer's roster. Each machine signer must have a distinct P-256
            public key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetailDto'
              example:
                type: IDEMPOTENCY_KEY_CONFLICT
                title: Idempotency Key Conflict
                status: 409
                detail: >-
                  The idempotency key was previously used with a different
                  request body. Idempotency keys are bound to the exact request
                  shape — replays must match the original.
                resolution: >-
                  Use a fresh idempotency key for the new request, or replay the
                  original request unchanged.
                docs: >-
                  https://conduit-v2.mintlify.app/errors#idempotency-key-conflict
                instance: /v2/...
                correlationId: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
                timestamp: '2026-01-15T09:30:00.000Z'
        '415':
          description: >-
            **UNSUPPORTED_MEDIA_TYPE**: The request carries a body with a
            Content-Type this endpoint cannot parse. JSON endpoints accept
            'application/json'; a body with no Content-Type header at all is
            assumed to be JSON. File-upload endpoints accept only
            'multipart/form-data' — JSON or undeclared bodies are rejected
            there.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetailDto'
              example:
                type: UNSUPPORTED_MEDIA_TYPE
                title: Unsupported Media Type
                status: 415
                detail: >-
                  The request carries a body with a Content-Type this endpoint
                  cannot parse. JSON endpoints accept 'application/json'; a body
                  with no Content-Type header at all is assumed to be JSON.
                  File-upload endpoints accept only 'multipart/form-data' — JSON
                  or undeclared bodies are rejected there.
                resolution: >-
                  Send the request body with the 'Content-Type:
                  application/json' header. For file uploads, use 'Content-Type:
                  multipart/form-data' — upload endpoints accept no other body
                  type.
                docs: https://conduit-v2.mintlify.app/errors#unsupported-media-type
                instance: /v2/...
                correlationId: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
                timestamp: '2026-01-15T09:30:00.000Z'
        '422':
          description: >-
            **SIGNERS_NOT_SUPPORTED**: Signers can only be managed on
            non-custodial wallets. This customer's wallet is custodial, so the
            backend signs on its behalf.


            **UNPROCESSABLE_ENTITY**: The request was well-formed but could not
            be processed due to semantic errors or business rule violations.


            **API_KEY_CREDENTIAL_NOT_SUPPORTED**: The request includes a machine
            signer (`credentialType: api_key`) in a context where api_key
            signers cannot be enrolled. This is reserved for future
            compatibility and should not be seen in normal operation.


            **WALLET_NO_PROVIDER_ACCOUNT**: The customer does not yet have a
            wallet account on the underlying provider. Wallet addresses cannot
            be created until the customer claims non-custodial control.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetailDto'
              example:
                type: SIGNERS_NOT_SUPPORTED
                title: Signers Not Supported
                status: 422
                detail: >-
                  Signers can only be managed on non-custodial wallets. This
                  customer's wallet is custodial, so the backend signs on its
                  behalf.
                resolution: >-
                  Claim the wallet as non-custodial via POST
                  /v2/customers/:id/wallets/claim-non-custodial before adding or
                  removing signers.
                docs: https://conduit-v2.mintlify.app/errors#signers-not-supported
                instance: /v2/...
                correlationId: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
                timestamp: '2026-01-15T09:30:00.000Z'
        '429':
          description: >-
            **RATE_LIMITED**: Too many requests. This error is returned by three
            independent checks: the per-organization bucket applied to every
            authenticated API request; the per-IP bucket applied to
            unauthenticated traffic before an API key is validated; and the
            per-IP bucket applied when repeated invalid API keys are submitted
            from the same address. Honor the Retry-After header (also exposed as
            retryAfterSeconds in the body) before retrying. Current limits and
            remaining budget are visible in X-RateLimit-Limit,
            X-RateLimit-Remaining, and X-RateLimit-Reset on rate-limited route
            responses.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitedErrorDto'
              example:
                type: RATE_LIMITED
                title: Rate Limited
                status: 429
                detail: >-
                  Too many requests. This error is returned by three independent
                  checks: the per-organization bucket applied to every
                  authenticated API request; the per-IP bucket applied to
                  unauthenticated traffic before an API key is validated; and
                  the per-IP bucket applied when repeated invalid API keys are
                  submitted from the same address. Honor the Retry-After header
                  (also exposed as retryAfterSeconds in the body) before
                  retrying. Current limits and remaining budget are visible in
                  X-RateLimit-Limit, X-RateLimit-Remaining, and
                  X-RateLimit-Reset on rate-limited route responses.
                resolution: >-
                  Sleep until Retry-After seconds have elapsed, then retry. For
                  sustained workloads exceeding the per-organization defaults,
                  request a rate-limit increase through your support contact.
                docs: https://conduit-v2.mintlify.app/errors#rate-limited
                instance: /v2/...
                correlationId: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
                timestamp: '2026-01-15T09:30:00.000Z'
                retryAfterSeconds: 3
        '500':
          description: >-
            **INTERNAL_ERROR**: An unexpected error occurred while processing
            your request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetailDto'
              example:
                type: INTERNAL_ERROR
                title: Internal Error
                status: 500
                detail: An unexpected error occurred while processing your request.
                resolution: >-
                  Retry the request after a brief delay. If the error persists,
                  contact support and include the correlationId from the error
                  response for investigation.
                docs: https://conduit-v2.mintlify.app/errors#internal-error
                instance: /v2/...
                correlationId: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
                timestamp: '2026-01-15T09:30:00.000Z'
components:
  schemas:
    AddWalletSignerDto:
      type: object
      properties:
        email:
          type: string
          format: email
          pattern: >-
            ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
          description: Email address of the signer to add
          example: signer@example.com
        name:
          description: Display name of the signer
          example: Jane Doe
          type: string
        role:
          description: >-
            admin = root-quorum member + signing-quorum member; signer =
            signing-quorum only
          type: string
          enum:
            - admin
            - signer
        credentialType:
          description: How this signer will stamp. api_key requires `publicKey`.
          type: string
          enum:
            - passkey
            - api_key
        publicKey:
          description: >-
            Machine-signer P-256 compressed public key (33 bytes, 02/03 prefix +
            64 hex chars, optional 0x prefix). Required when
            credentialType=api_key.
          example: 02a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2
          type: string
      required:
        - email
      additionalProperties: false
    AddWalletSignerResponseDto:
      type: object
      properties:
        id:
          type: string
          pattern: ^wsg_[0-9A-Za-z]{22}$
          description: Unique wallet signer identifier
        email:
          type: string
          description: Signer's email address
          example: signer@example.com
        name:
          type: string
          description: Signer's display name
          example: Jane Doe
          nullable: true
        role:
          description: >-
            admin = root-quorum member + signing-quorum member; signer =
            signing-quorum only
          type: string
          enum:
            - admin
            - signer
        credentialType:
          description: How this signer stamps requests
          type: string
          enum:
            - passkey
            - api_key
        passkeyCount:
          type: integer
          minimum: 0
          maximum: 9007199254740991
          description: Number of passkeys enrolled for this signer
          example: 0
        status:
          description: Current signer status
          type: string
          enum:
            - pending_activation
            - activating
            - active
            - pending_removal
            - removed
            - error
        createdAt:
          type: string
          format: date-time
          description: Timestamp when the signer was created
          example: '2026-01-15T09:30:00.000Z'
        updatedAt:
          type: string
          format: date-time
          description: Timestamp when the signer was last updated
          example: '2026-01-15T09:30:00.000Z'
        verificationUrl:
          type: string
          description: >-
            Synchronous URL for this add, or null when none applies. Read
            `urlAudience` to know who it is for before delivering it — a passkey
            add returns the signer's enrollment link, an api_key add pending
            approval returns a customer admin's co-stamp link. On a live roster
            a `"signer"` link is the FIRST of two links, not full self-service:
            after the signer enrolls their passkey the add parks a roster-add
            ceremony for an admin co-stamp, whose link arrives only on the
            `wallet_ceremony.awaiting_admin_approval` webhook (carrying the
            ceremony's `ceremonyId`).
          example: >-
            https://app.conduit.financial/verify/mtQzSU2hdy0DuZ6za2IHIoVDgXzshrFtN38kMULRDFw
          nullable: true
        urlAudience:
          type: string
          enum:
            - signer
            - admin
          description: >-
            Audience of `verificationUrl`: `signer` = the new signer's
            credential-enrollment link (deliver to the signer) — on a live
            roster this is only the first of two links, the second being an
            admin co-stamp delivered on the
            `wallet_ceremony.awaiting_admin_approval` webhook; `admin` = a
            customer admin's approval link (deliver to an admin; also delivered
            via the `wallet_ceremony.awaiting_admin_approval` webhook); null
            when there is no URL.
          nullable: true
        awaitingProvider:
          description: >-
            True only while the parked activity is still resolving at the
            custody provider — `verificationUrl`/`urlAudience` are null here
            too, but unlike a synchronously-admitted add there is a `ceremonyId`
            to track and nothing yet for any human to approve. Absent on every
            other outcome.
          type: boolean
          enum:
            - true
        machineApproval:
          description: >-
            Additional material for a machine (api_key) add that parks for
            approval on a roster carrying an ACTIVE api_key admin. It is handed
            back ALONGSIDE `verificationUrl` (`urlAudience: "admin"`) and the
            `wallet_ceremony.awaiting_admin_approval` webhook, which are always
            present — approve either way. Stamp `approvalMaterial` with an
            ACTIVE api_key admin's P-256 key and POST `{ method: "api_key",
            credential }` to `/v2/verifications/{token}/complete` (credential is
            a JSON string of `{ signedBody, stamp, organizationId }`) to
            activate the signer — the same stamp-and-approve step every machine
            governance ceremony uses. Absent when the roster has no api_key
            admin to stamp.
          type: object
          properties:
            token:
              type: string
              description: >-
                Verification token. Approve by POSTing the admin stamp to
                `/v2/verifications/{token}/complete` as `{ method: "api_key",
                credential }`, where credential is a JSON string of `{
                signedBody, stamp, organizationId }`.
            approvalMaterial:
              type: object
              properties:
                activityId:
                  type: string
                  description: Signing activity id the admin stamp approves.
                fingerprint:
                  type: string
                  description: Activity fingerprint the stamped body must carry.
                subOrganizationId:
                  type: string
                  description: Signing sub-organization the stamp must target.
              required:
                - activityId
                - fingerprint
                - subOrganizationId
          required:
            - token
            - approvalMaterial
      required:
        - id
        - email
        - name
        - role
        - credentialType
        - passkeyCount
        - status
        - createdAt
        - updatedAt
        - verificationUrl
        - urlAudience
    ValidationErrorDto:
      type: object
      properties:
        type:
          type: string
          description: Machine-readable error code
          example: CUSTOMER_NOT_FOUND
        title:
          type: string
          description: Human-readable error type label
          example: Customer Not Found
        status:
          type: number
          description: HTTP status code
          example: 404
        detail:
          type: string
          description: Human-readable explanation of this occurrence
          example: Customer with id cus_034A0gCCVsxdV2PjHLx9k1 not found
        resolution:
          type: string
          description: What the developer should do to resolve this error
          example: >-
            Verify the customer ID. Check you are using the correct API key for
            this organization.
        docs:
          type: string
          description: URL to error documentation
          example: https://conduit-v2.mintlify.app/errors#customer-not-found
        instance:
          type: string
          description: Request path that produced the error
          example: /v2/customers/cus_034A0gCCVsxdV2PjHLx9k1
        correlationId:
          description: Request correlation ID
          example: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
          type: string
        timestamp:
          type: string
          description: ISO 8601 UTC timestamp
          example: '2026-04-27T20:00:00.000Z'
        details:
          description: >-
            Additional structured data for domain-specific errors (e.g. missing
            field lists, pair info)
        errors:
          type: array
          items:
            type: object
            properties:
              pointer:
                type: string
                description: JSON pointer to the invalid field
                example: /email
              detail:
                type: string
                description: What is wrong with this field
                example: Invalid email format
              allowedValues:
                description: The values this field accepts, when it is a closed set
                example:
                  - ach
                  - fedwire
                  - rtp
                type: array
                items:
                  type: string
              category:
                description: >-
                  Class of blocker (requirements-validator output only). 'field'
                  = form-field gap, 'document' = missing or insufficient
                  document (including per-UBO document slots), 'individual' =
                  required person missing.
                example: field
                type: string
                enum:
                  - field
                  - document
                  - individual
            required:
              - pointer
              - detail
      required:
        - type
        - title
        - status
        - detail
        - resolution
        - docs
        - instance
        - timestamp
    ProblemDetailDto:
      type: object
      properties:
        type:
          type: string
          description: Machine-readable error code
          example: CUSTOMER_NOT_FOUND
        title:
          type: string
          description: Human-readable error type label
          example: Customer Not Found
        status:
          type: number
          description: HTTP status code
          example: 404
        detail:
          type: string
          description: Human-readable explanation of this occurrence
          example: Customer with id cus_034A0gCCVsxdV2PjHLx9k1 not found
        resolution:
          type: string
          description: What the developer should do to resolve this error
          example: >-
            Verify the customer ID. Check you are using the correct API key for
            this organization.
        docs:
          type: string
          description: URL to error documentation
          example: https://conduit-v2.mintlify.app/errors#customer-not-found
        instance:
          type: string
          description: Request path that produced the error
          example: /v2/customers/cus_034A0gCCVsxdV2PjHLx9k1
        correlationId:
          description: Request correlation ID
          example: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
          type: string
        timestamp:
          type: string
          description: ISO 8601 UTC timestamp
          example: '2026-04-27T20:00:00.000Z'
        details:
          description: >-
            Additional structured data for domain-specific errors (e.g. missing
            field lists, pair info)
      required:
        - type
        - title
        - status
        - detail
        - resolution
        - docs
        - instance
        - timestamp
    RateLimitedErrorDto:
      type: object
      properties:
        type:
          type: string
          description: Machine-readable error code
          example: CUSTOMER_NOT_FOUND
        title:
          type: string
          description: Human-readable error type label
          example: Customer Not Found
        status:
          type: number
          description: HTTP status code
          example: 404
        detail:
          type: string
          description: Human-readable explanation of this occurrence
          example: Customer with id cus_034A0gCCVsxdV2PjHLx9k1 not found
        resolution:
          type: string
          description: What the developer should do to resolve this error
          example: >-
            Verify the customer ID. Check you are using the correct API key for
            this organization.
        docs:
          type: string
          description: URL to error documentation
          example: https://conduit-v2.mintlify.app/errors#customer-not-found
        instance:
          type: string
          description: Request path that produced the error
          example: /v2/customers/cus_034A0gCCVsxdV2PjHLx9k1
        correlationId:
          description: Request correlation ID
          example: 00469ea4-52c1-4ffa-bd05-9f28b236a5fe
          type: string
        timestamp:
          type: string
          description: ISO 8601 UTC timestamp
          example: '2026-04-27T20:00:00.000Z'
        details:
          description: >-
            Additional structured data for domain-specific errors (e.g. missing
            field lists, pair info)
        retryAfterSeconds:
          type: integer
          minimum: 0
          exclusiveMinimum: true
          maximum: 9007199254740991
          description: Seconds to wait before retrying
          example: 3
      required:
        - type
        - title
        - status
        - detail
        - resolution
        - docs
        - instance
        - timestamp
        - retryAfterSeconds
  securitySchemes:
    api-key:
      type: apiKey
      in: header
      name: x-api-key

````