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

# Create an Instrument for a Beneficiary

> Attach a payment instrument to a beneficiary. The credentials you submit
(bank account numbers, wallet addresses, card PANs) are tokenized in Basis
Theory on receipt — Anton's core database stores only a token reference, a
display-only masked value, and a content fingerprint used for cross-merchant
deduplication.

The request body shape depends on the `method` — each method has a distinct
credential schema. See the [Instruments methods endpoint](#tag/Reference-Data/operation/listPaymentMethods)
for the full per-country method catalog.

Requires an `Idempotency-Key` header.




## OpenAPI

````yaml POST /v1/beneficiaries/{id}/instruments
openapi: 3.1.0
info:
  title: Anton Payments API
  version: 1.0.0
  summary: Cross-border payout infrastructure. Fiat, stablecoin, and crypto.
  description: >
    The Anton Payments merchant API. Versioned, idempotent, cursor-paginated.


    - **Authentication**: OAuth 2.0 client_credentials with DPoP
    proof-of-possession (RFC 6749 §4.4 + RFC 9449). Programmatic clients
    exchange `(client_id, client_secret)` for a short-lived access token at
    `POST /oauth/token`, then send each request with `Authorization: DPoP
    <access_token>` plus a per-request `DPoP: <proof>` header. Static API keys
    are not accepted on v1.

    - Base URLs: `https://api.antonpayments.com` (production),
    `https://api.antonpayments.dev` (sandbox).

    - Monetary amounts are decimal strings. Never floats.

    - Timestamps are RFC 3339 UTC.

    - All mutating endpoints support the `Idempotency-Key` header.

    - Anton's OAuth public signing key is published at `GET
    /.well-known/jwks.json` (5-minute cache; RFC 8615).


    See the Cross-Cutting section of the docs for idempotency, pagination, rate
    limits, errors, webhook events, and webhook signing.
  contact:
    name: Anton Payments Support
    url: https://help.antonpayments.com
  license:
    name: Proprietary
    url: https://www.antonpayments.com
servers:
  - url: https://api.antonpayments.com
    description: Production
  - url: https://api.antonpayments.dev
    description: Sandbox
security:
  - oauthDPoP: []
    dpopHeader: []
tags:
  - name: Authentication
    description: >-
      OAuth 2.0 token endpoint and JWKS publication. See the API description for
      the full DPoP-bound flow.
  - name: OAuth Clients
    description: >-
      Manage OAuth credentials (programmatic access). Portal-only — JWT auth
      required.
  - name: Reference Data
    description: Currencies, countries, and supported payment methods.
  - name: Beneficiaries
    description: Create and manage the people and businesses you pay.
  - name: Instruments
    description: >-
      Payment instruments attached to beneficiaries — bank accounts, wallets,
      cards.
  - name: Payouts
    description: Initiate and track payouts.
  - name: Batches
    description: CSV-driven bulk payout processing.
  - name: Balances
    description: Merchant balance by currency.
  - name: Accounts
    description: Virtual accounts for merchant funding.
  - name: Webhooks
    description: Subscribe to event notifications.
  - name: Documents
    description: Upload and manage KYB and supporting documents.
  - name: RFIs
    description: Respond to Requests for Information raised during review.
  - name: Pricing
    description: Read merchant pricing plans and quote fees.
  - name: FX
    description: Quote, lock, and execute currency exchanges between balances.
  - name: Corridors
    description: Active cross-border corridors for your merchant.
  - name: Balance Alerts
    description: >-
      Per-currency low-balance thresholds that drive the `balance.low` webhook
      event.
  - name: Sandbox
    description: Reset and seed your sandbox environment.
  - name: Merchant
    description: Merchant profile, branding, preferences, and security posture.
  - name: API Keys
    description: Issue, list, and revoke API keys.
  - name: Users
    description: Self-service profile, MFA, and team management.
  - name: Notifications
    description: Per-user notification channels and preferences.
  - name: Velocity
    description: Merchant-scoped risk rules and what-if simulation.
  - name: Engine
    description: Glass-box view of Anton's risk intelligence.
  - name: Onboarding
    description: Authenticated KYB onboarding draft and submission.
  - name: Public Onboarding
    description: >-
      Session-authenticated hosted onboarding flow. Not intended for SDK
      consumption.
paths:
  /v1/beneficiaries/{id}/instruments:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          pattern: ^ben_[a-zA-Z0-9]+$
    post:
      tags:
        - Instruments
      summary: Create an instrument for a beneficiary
      description: >
        Attach a payment instrument to a beneficiary. The credentials you submit

        (bank account numbers, wallet addresses, card PANs) are tokenized in
        Basis

        Theory on receipt — Anton's core database stores only a token reference,
        a

        display-only masked value, and a content fingerprint used for
        cross-merchant

        deduplication.


        The request body shape depends on the `method` — each method has a
        distinct

        credential schema. See the [Instruments methods
        endpoint](#tag/Reference-Data/operation/listPaymentMethods)

        for the full per-country method catalog.


        Requires an `Idempotency-Key` header.
      operationId: createInstrumentForBeneficiary
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InstrumentCreateRequest'
      responses:
        '201':
          description: Instrument created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Instrument'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      description: >
        Unique key identifying this operation. Sending the same key twice
        returns the original

        response instead of creating a duplicate. Keys are retained for 24
        hours.
      required: true
      schema:
        type: string
        maxLength: 255
  schemas:
    InstrumentCreateRequest:
      type: object
      required:
        - method
      description: >
        Create an instrument attached to a beneficiary.


        The `credentials` object shape varies by `method`. A few common shapes:


        - `iban`: `{ "iban": "GB82WEST12345698765432", "bic": "WESTGB22" }` (BIC
        optional)

        - `uk_bank`: `{ "account_number": "12345678", "sort_code": "123456" }`

        - `us_bank`: `{ "routing_number": "026073150", "account_number": "...",
        "account_type": "checking" }`

        - `crypto`: `{ "wallet_address": "0x...", "network": "ethereum",
        "token_symbol": "USDC" }`

        - `card`: `{ "pan": "...", "expiry_month": 12, "expiry_year": 2028 }`
        (routed through PCI vault)


        Call `GET /v1/payment-methods?country=XX` for the complete per-country
        catalog

        with the exact credential schema required.
      properties:
        method:
          $ref: '#/components/schemas/PaymentMethodCode'
        currency:
          $ref: '#/components/schemas/CurrencyCode'
        country:
          $ref: '#/components/schemas/CountryCode'
        label:
          type: string
          description: >-
            Merchant-visible label for this instrument (e.g. "Payroll - primary
            account").
          maxLength: 255
        credentials:
          type: object
          description: Method-specific credential fields. Tokenized on receipt.
          additionalProperties: true
        is_default:
          type: boolean
          description: >-
            Make this the default instrument for the beneficiary. The previous
            default (if any) is unflagged.
          default: false
        end_user_ip:
          type: string
    Instrument:
      type: object
      description: >
        A payment destination attached to a beneficiary. Credentials (account
        numbers,

        wallet addresses, card PANs) are tokenized in Basis Theory and never
        returned

        by the API. Only masked display fields and method metadata are exposed.
      required:
        - id
        - beneficiary_id
        - merchant_id
        - method
        - status
        - is_default
        - created_at
        - updated_at
      properties:
        id:
          type: string
          pattern: ^ins_[a-zA-Z0-9]+$
          example: ins_01HX8Z9K0M2N3P4Q5R6S7T8UA2
        beneficiary_id:
          type: string
          pattern: ^ben_[a-zA-Z0-9]+$
        merchant_id:
          type: string
          pattern: ^mer_[a-zA-Z0-9]+$
        method:
          $ref: '#/components/schemas/PaymentMethodCode'
        currency:
          $ref: '#/components/schemas/CurrencyCode'
        country:
          $ref: '#/components/schemas/CountryCode'
        label:
          type: string
          description: Merchant-visible label.
        display_last4:
          type: string
          description: >-
            Last 4 characters of the primary credential (account number / PAN /
            wallet address), for display.
        display_bank:
          type: string
          description: Bank name derived from routing details, for display.
        display_network:
          type: string
          description: Card network or chain, for display (e.g. `visa`, `ethereum`).
        masked_account:
          type: string
          description: Fully masked credential for list views.
          example: '****5432'
        status:
          type: string
          enum:
            - active
            - disabled
        is_default:
          type: boolean
          description: Whether this is the beneficiary's default instrument for payouts.
        created_at:
          $ref: '#/components/schemas/Timestamp'
        updated_at:
          $ref: '#/components/schemas/Timestamp'
      example:
        id: ins_01HX8Z9K0M2N3P4Q5R6S7T8UA2
        beneficiary_id: ben_01HX8Z9K0M2N3P4Q5R6S7T8UA1
        merchant_id: mer_01HX8Z9K0M2N3P4Q5R6S7T8UZZ
        method: iban
        currency: EUR
        country: DE
        label: Primary EUR account
        display_last4: '5432'
        display_bank: Deutsche Bank
        masked_account: DE89****5432
        status: active
        is_default: true
        created_at: '2026-04-15T14:30:00Z'
        updated_at: '2026-04-15T14:30:00Z'
    PaymentMethodCode:
      type: string
      description: >
        Credential format of a payment instrument — named by what data is
        stored,

        not by the rail that delivers the funds. One credential type can route
        to

        multiple rails (e.g. an IBAN can go via SEPA, SEPA Instant, TARGET2,
        SWIFT,

        or CHAPS — the rail is selected at payout time).


        Query `GET /v1/payment-methods` for the full country-specific catalog

        including per-method credential schemas.
      enum:
        - iban
        - uk_bank
        - us_bank
        - ca_bank
        - au_bank
        - nz_bank
        - jp_bank
        - in_bank
        - za_bank
        - ng_bank
        - ph_bank
        - cl_bank
        - co_bank
        - swift
        - clabe
        - cbu
        - cci
        - pix
        - upi
        - interac
        - paynow
        - fps_hk
        - promptpay
        - card
        - crypto
        - mobile_money
    CurrencyCode:
      type: string
      description: ISO 4217 three-letter currency code.
      pattern: ^[A-Z]{3}$
      example: USD
    CountryCode:
      type: string
      description: ISO 3166-1 alpha-2 country code.
      pattern: ^[A-Z]{2}$
      example: US
    Timestamp:
      type: string
      format: date-time
      description: RFC 3339 / ISO 8601 timestamp in UTC.
      example: '2026-04-15T14:30:00Z'
    ErrorEnvelope:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - message
          properties:
            message:
              type: string
              description: Human-readable description of what went wrong.
            code:
              type: string
              description: Machine-readable error code. Branch on this, not on `message`.
              example: insufficient_balance
      example:
        error:
          message: insufficient funds for this payout
          code: insufficient_balance
    ValidationErrorEnvelope:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - message
            - code
          properties:
            message:
              type: string
              example: request failed validation
            code:
              type: string
              enum:
                - validation_error
            details:
              type: array
              description: Field-level validation errors.
              items:
                type: object
                required:
                  - field
                  - message
                properties:
                  field:
                    type: string
                    description: Dotted JSON path to the offending field.
                    example: individual.date_of_birth
                  message:
                    type: string
                    example: must be in YYYY-MM-DD format
      example:
        error:
          message: request failed validation
          code: validation_error
          details:
            - field: individual.first_name
              message: is required
            - field: country
              message: must be a valid ISO-3166 alpha-2 country code
  responses:
    Unauthorized:
      description: Missing or invalid API key, or key used against the wrong environment.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          examples:
            missing_key:
              summary: Missing bearer token
              value:
                error:
                  code: unauthorized
                  message: missing or invalid credentials
            wrong_environment:
              summary: Test key used against production
              value:
                error:
                  code: key_environment_mismatch
                  message: this API key is not valid for this environment
    NotFound:
      description: The resource does not exist, or belongs to a different merchant.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    IdempotencyConflict:
      description: >-
        The same `Idempotency-Key` was previously used with a different request
        body.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    ValidationFailed:
      description: The request body failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationErrorEnvelope'
    RateLimited:
      description: Rate limit exceeded. See `Retry-After`.
      headers:
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
  headers:
    Retry-After:
      description: Seconds to wait before retrying. Included on 429 responses.
      schema:
        type: integer
  securitySchemes:
    oauthDPoP:
      type: oauth2
      description: >
        OAuth 2.0 client_credentials grant (RFC 6749 §4.4) bound to a DPoP
        keypair (RFC 9449).


        **Flow** (every authenticated `/v1` call requires both an access token
        AND a fresh per-request DPoP proof):


        1. Register a credential via the merchant portal. Anton issues a
        `client_id` (`ant_oc_<env>_<32hex>`) and a `client_secret`
        (`ant_ocs_<env>_<48hex>`, shown ONCE). The portal generates an ES256 or
        Ed25519 DPoP keypair in your browser; you store the private half.

        2. Mint an access token: `POST /oauth/token` with `Authorization: Basic
        <client_id:client_secret>` and `Content-Type:
        application/x-www-form-urlencoded`. Body:
        `grant_type=client_credentials`. A `DPoP` header carrying a proof signed
        for the token endpoint is required (no `ath` claim on this proof).

        3. Use the token: send `Authorization: DPoP <access_token>` plus a fresh
        `DPoP: <proof>` header on every `/v1` request. The proof JWT MUST carry
        `htm` (request method), `htu` (request URL, no query/fragment), `iat`
        (within ±60s), `jti` (unique within 5 min), and `ath` (SHA-256 of the
        access token, base64url).


        Tokens expire in **1 hour** in production / staging and **8 hours** in
        sandbox. There are no refresh tokens — call `/oauth/token` again with
        your secret. Anton's public signing key is published at
        `/.well-known/jwks.json`.


        OpenAPI 3.0 has no native DPoP scheme; this declaration plus
        `dpopHeader` together convey both the access-token Authorization and the
        per-request proof header.
      flows:
        clientCredentials:
          tokenUrl: /oauth/token
          scopes: {}
    dpopHeader:
      type: apiKey
      in: header
      name: DPoP
      description: >
        Per-request DPoP proof JWT (RFC 9449). MUST accompany the
        `Authorization: DPoP <access_token>` header on every protected
        operation. The proof is signed by the merchant's private DPoP key and
        carries `htm`, `htu`, `iat`, `jti`, and `ath` claims.

````