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

# Transfer funds

> Send from a **custodial** wallet on either rail: `type: "public"` is a
standard ERC-20 stablecoin transfer; `type: "private"` is a cAROUSD
`confidentialTransfer` whose amount is FHE-encrypted on-chain.

Blocks up to ~90 s for the receipt; may return `PENDING`.




## OpenAPI

````yaml /api-reference/openapi.yaml post /transfer
openapi: 3.1.0
info:
  title: AroPay API
  version: 1.0.0
  description: |
    The AroPay API for orchestrating sealed, private payments on public
    ledgers, built on the Aro Confidential Rails (Zama Protocol FHE). The
    current deployment is an MVP sandbox for B2B users on Ethereum Sepolia,
    with Mainnet to follow.

    Every response (except the flat Sandbox probes)
    uses the shared envelope: `{ "ok": true, "data": … }` on success and
    `{ "ok": false, "error": { "code", "message", "details?" } }` on failure.

    Amounts are decimal strings in human units (e.g. `"125.50"`). Write
    requests must send `Content-Type: application/json`.
  contact:
    name: Aro Media
    url: https://aro.media
servers:
  - url: https://aropay.aro.media/api/v1
    description: Sandbox
  - url: http://aropay.localhost:3000/api/v1
    description: Local development
security:
  - apiKeyAuth: []
  - sessionCookie: []
tags:
  - name: Auth
    description: Password, TOTP, and passkey login; session inspection and logout.
  - name: Profile & security
    description: Profile, password, two-factor authentication, and passkey management.
    x-group: Profile & security
  - name: API keys
    description: Programmatic credentials. Creation and revocation are session-only.
  - name: Wallets
    description: Custodial and external (watch-only) wallets.
  - name: Balances
    description: Balance triples and lightweight gas reads.
  - name: Money movement
    description: Faucet funding, minting, transfers, and redemptions.
  - name: Transactions
    description: History, single-transaction reads, and notarized receipts.
  - name: Sandbox
    description: Unauthenticated status and echo probes with a flat response shape.
paths:
  /transfer:
    post:
      tags:
        - Money movement
      summary: Transfer funds
      description: |
        Send from a **custodial** wallet on either rail: `type: "public"` is a
        standard ERC-20 stablecoin transfer; `type: "private"` is a cAROUSD
        `confidentialTransfer` whose amount is FHE-encrypted on-chain.

        Blocks up to ~90 s for the receipt; may return `PENDING`.
      operationId: transferFunds
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - walletId
                - to
                - amount
                - type
              properties:
                walletId:
                  type: string
                  description: Sending wallet; must be custodial.
                to:
                  type: string
                  pattern: ^0x[a-fA-F0-9]{40}$
                  description: Recipient address.
                amount:
                  type: string
                  description: Decimal string in human units.
                type:
                  type: string
                  enum:
                    - public
                    - private
                  description: Which rail to use.
            example:
              walletId: ckwlt0001abcd
              to: '0x52aE1b7c86D2f1e9021a1B4a9c3B8d55E37F9021'
              amount: '25'
              type: private
      responses:
        '201':
          description: Transfer transaction.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionEnvelope'
              example:
                ok: true
                data:
                  transaction:
                    id: cktxn0003abcd
                    type: PRIVATE_TRANSFER
                    status: CONFIRMED
                    chainId: 11155111
                    amount: '25.00'
                    token: cAROUSD
                    txHash: 0x9ac2…
                    settlementTxHash: null
                    explorerUrl: https://sepolia.etherscan.io/tx/0x9ac2…
                    fromAddress: '0x8Ba1f109551bD432803012645Ac136ddd64DBA72'
                    toAddress: '0x52aE1b7c86D2f1e9021a1B4a9c3B8d55E37F9021'
                    counterparty: null
                    walletId: ckwlt0001abcd
                    error: null
                    metadata: null
                    createdAt: '2026-08-13T09:45:00.000Z'
                    updatedAt: '2026-08-13T09:45:38.000Z'
        '400':
          description: >-
            Validation failure, invalid recipient, external wallet, or
            insufficient balance on the chosen rail.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                ok: false
                error:
                  code: invalid_recipient
                  message: Recipient must be a valid address.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/AccountDisabled'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '502':
          description: Transfer reverted on-chain.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                ok: false
                error:
                  code: transfer_failed
                  message: Transfer reverted on-chain.
components:
  schemas:
    TransactionEnvelope:
      type: object
      required:
        - ok
        - data
      properties:
        ok:
          const: true
        data:
          type: object
          required:
            - transaction
          properties:
            transaction:
              $ref: '#/components/schemas/Transaction'
    ErrorResponse:
      type: object
      description: The shared failure envelope.
      required:
        - ok
        - error
      properties:
        ok:
          const: false
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Machine-readable error code; match on this, not `message`.
            message:
              type: string
            details:
              description: Structured context, e.g. per-field validation issues.
    Transaction:
      type: object
      description: A sandbox operation and its on-chain outcome.
      required:
        - id
        - type
        - status
        - chainId
        - amount
        - token
        - txHash
        - settlementTxHash
        - explorerUrl
        - fromAddress
        - toAddress
        - counterparty
        - walletId
        - error
        - metadata
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          examples:
            - cktxn0001abcd
        type:
          type: string
          enum:
            - FUND
            - MINT
            - TRANSFER
            - PRIVATE_TRANSFER
            - REDEEM
        status:
          type: string
          enum:
            - PENDING
            - CONFIRMED
            - SETTLING
            - SETTLED
            - FAILED
          description: |
            `PENDING` → `CONFIRMED`/`FAILED` for most types; redeems go
            `PENDING` → `SETTLING` → `SETTLED`. Terminal states: `CONFIRMED`,
            `SETTLED`, `FAILED`.
        chainId:
          type: integer
          examples:
            - 11155111
        amount:
          type: string
          description: Decimal string in human units.
        token:
          type: string
          description: Token symbol the amount denominates.
        txHash:
          type:
            - string
            - 'null'
          description: First-leg transaction hash.
        settlementTxHash:
          type:
            - string
            - 'null'
          description: Second-leg hash; redeem payout or the faucet's stablecoin leg.
        explorerUrl:
          type:
            - string
            - 'null'
          description: Block-explorer link for `txHash`.
        fromAddress:
          type:
            - string
            - 'null'
        toAddress:
          type:
            - string
            - 'null'
        counterparty:
          type:
            - string
            - 'null'
        walletId:
          type:
            - string
            - 'null'
        error:
          type:
            - string
            - 'null'
          description: Failure context when `status` is `FAILED`.
        metadata:
          description: Operation-specific context (object or null).
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
  responses:
    Unauthorized:
      description: Missing or invalid credential.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            ok: false
            error:
              code: invalid_api_key
              message: Invalid API key.
    AccountDisabled:
      description: The account has been deactivated.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            ok: false
            error:
              code: account_disabled
              message: This account is disabled.
    NotFound:
      description: Resource not found within this account.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            ok: false
            error:
              code: not_found
              message: Resource not found.
    RateLimited:
      description: Rate limit exceeded.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            ok: false
            error:
              code: rate_limited
              message: Too many requests. Try again shortly.
    InternalError:
      description: Unexpected server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            ok: false
            error:
              code: internal_error
              message: An unexpected error occurred.
  securitySchemes:
    apiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: aro_sk_…
      description: |
        AroPay API key, sent as `Authorization: Bearer aro_sk_…`. Created in
        the dashboard under Settings → API keys. Takes precedence over a
        session cookie when both are present.
      x-default: aro_sk_your_key_here
    sessionCookie:
      type: apiKey
      in: cookie
      name: aropay_session
      description: |
        Browser session cookie minted by `POST /auth/login` (or passkey
        login). httpOnly, `SameSite=Lax`, 24 h TTL. Endpoints marked
        **Session-only** accept only this credential and return
        `403 session_required` for API keys.

````