> ## 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.

# Confirm a Beneficiary Import

> Materializes beneficiaries for every row that passed preview validation.
Invalid rows from the preview phase are skipped. Rows that pass preview
but fail at create time (duplicate identity, vault failure, etc.) are
reported in `errors[]`.

The import row is marked `confirmed` once this call completes — even
on partial failure. To re-run a subset, edit the source CSV and upload
a fresh import.

Requires an `Idempotency-Key` header.




## OpenAPI

````yaml POST /v1/beneficiaries/import/{importID}/confirm
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).


    **Capabilities and scopes.** Every account carries a capability set
    (`payouts`, `intelligence`) and every

    credential carries a scope set validated against it at creation.
    AI-compliance-only accounts hold only

    `intelligence` — all payout-surface endpoints return `403
    capability_required` for them. A credential

    minted without a scope returns `403 insufficient_scope` on that surface.
    Effective access is

    `scopes ∩ capabilities`. Access tokens embed the grants as a space-delimited
    `scope` claim, echoed in the

    token response.


    **What machine credentials can never do.** Approval decisions (payout
    approve/reject — maker-checker

    requires a human identity) and detokenized PII readback (beneficiary PII,
    verification name reveal,

    captured-document viewing) are dashboard-only: those operations require a
    signed-in portal user with the

    right role, and every access is audit-logged. Machine credentials can
    deposit and replace PII — your

    system is its source — but can never read it back, so a leaked credential
    cannot harvest identities.


    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: Intelligence
    description: >-
      Normalized payee, instrument, payout, and merchant risk intelligence
      evaluations.
  - name: Verifications
    description: >-
      KYC/KYB-as-a-service — verify the identity of your customers and their
      businesses through Anton-hosted flows, with sanctions screening built in.
  - 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/import/{importID}/confirm:
    parameters:
      - name: importID
        in: path
        required: true
        schema:
          type: string
          pattern: ^imp_[a-zA-Z0-9]+$
    post:
      tags:
        - Beneficiaries
      summary: Confirm a beneficiary import
      description: |
        Materializes beneficiaries for every row that passed preview validation.
        Invalid rows from the preview phase are skipped. Rows that pass preview
        but fail at create time (duplicate identity, vault failure, etc.) are
        reported in `errors[]`.

        The import row is marked `confirmed` once this call completes — even
        on partial failure. To re-run a subset, edit the source CSV and upload
        a fresh import.

        Requires an `Idempotency-Key` header.
      operationId: confirmBeneficiaryImport
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Confirm completed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/BeneficiaryImportConfirm'
        '400':
          description: >-
            `invalid_import_id` — the path parameter does not look like an
            `imp_` id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: >-
            `import_not_found` — no preview row matches this id for the calling
            merchant.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '409':
          description: >
            Confirm cannot proceed. One of:

            - `import_already_confirmed` — a previous call already materialized
            this import.

            - `import_expired` — the 24-hour TTL has elapsed; re-upload the
            file.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '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:
    BeneficiaryImportConfirm:
      type: object
      description: Result of `POST /v1/beneficiaries/import/{import_id}/confirm`.
      required:
        - import_id
        - summary
        - created_ids
        - errors
      properties:
        import_id:
          type: string
          pattern: ^imp_[a-zA-Z0-9]+$
        summary:
          type: object
          required:
            - created
            - skipped
            - failed
          properties:
            created:
              type: integer
              description: Beneficiaries created in this confirm call.
            skipped:
              type: integer
              description: Rows that failed validation at preview time.
            failed:
              type: integer
              description: Rows that passed preview validation but failed at create time.
        created_ids:
          type: array
          items:
            type: string
            pattern: ^ben_[a-zA-Z0-9]+$
        errors:
          type: array
          items:
            type: object
            required:
              - row_number
              - error
            properties:
              row_number:
                type: integer
              error:
                type: string
    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
  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
    RateLimited:
      description: >-
        Rate limit exceeded. See `Retry-After`. The `X-RateLimit-*` headers are
        present on every API response, not only on 429s — they are documented
        here because this is where clients act on them.
      headers:
        Retry-After:
          $ref: '#/components/headers/Retry-After'
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          examples:
            rate_limit_exceeded:
              summary: Retry after the limiter resets
              value:
                error:
                  code: rate_limit_exceeded
                  message: rate limit exceeded, retry after 60 seconds
  headers:
    Retry-After:
      description: Seconds to wait before retrying. Included on 429 responses.
      schema:
        type: integer
    X-RateLimit-Limit:
      description: Maximum requests permitted in the current window.
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests remaining in the current window.
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Unix timestamp when the current window resets.
      schema:
        type: integer
  securitySchemes:
    oauthDPoP:
      type: http
      scheme: DPoP
      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`.


        **Scopes** (requested at `POST /oauth/token`, returned in the `scope`
        response field):


        | Scope | Grants |

        |---|---|

        | `payouts` | Money movement — payouts, batches, beneficiaries,
        instruments, balances, funding, FX. |

        | `intelligence` | Anton Intelligence — screening evaluations and
        evidence. |


        This scheme is declared as `http`/`DPoP` rather than `oauth2` so that
        generated examples show the correct `Authorization: DPoP <access_token>`
        header. Sending `Authorization: Bearer <access_token>` returns `401
        unauthorized` — the token is sender-constrained and the scheme is not
        interchangeable.
    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.

````