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

# Submit Pool-Account Payment Proof

> Submits proof of a deposit made to the business pool account. The request creates a business deposit transaction in `IN_REVIEW` status; an operator confirms the bank inflow before the funds are credited. The response returns that transaction. Duplicate submissions of the same business, customer, amount, reference, timestamp and sender details within the configured idempotency window are rejected.

Submit proof of a deposit made into your business's [pool account](/api-reference/endpoint/payment-methods/pool-account). The request creates a business deposit transaction in `IN_REVIEW`; an operator confirms the bank inflow before the funds are credited.

## Flow

<Steps>
  <Step title="Upload the proof">
    Call [Generate Upload URL](/api-reference/endpoint/media/generate-upload-url) with `type: "transaction"` and `PUT` the proof file (bank receipt, screenshot, etc.) to the returned presigned URL.

    <Warning>
      The `type` matters. A URL requested with `type: "user"` uploads to a different bucket; passing that `key` here is rejected as not found.
    </Warning>
  </Step>

  <Step title="Submit the proof">
    Call this endpoint with the deposit `amount`, the `countryCode` of the pool account, the pool-account `reference` (see below), the S3 `fileKey` returned in step 1, and the payment `timestamp`. Optionally attach `senderDetails` (name, account number, bank, country) to help reconciliation.
  </Step>

  <Step title="Wait for confirmation">
    The response is a transaction in `IN_REVIEW`. Subscribe to [Transaction Events](/api-reference/endpoint/webhooks/transaction-events) to be notified when the operator confirms and the status transitions.
  </Step>
</Steps>

## Choosing the `reference`

* Credit an **end customer**: pass the customer's `reference` (the shortened value returned on customer reads; falls back to the customer id when none is assigned). `customerId` must match that customer.
* Credit the **business itself**: pass the business's own pool-account reference from [Get Pool Account](/api-reference/endpoint/payment-methods/pool-account). Routing does not use `customerId` in this case.

## Idempotency

Duplicate submissions with the same business, `customerId`, `amount`, `reference`, `timestamp`, and `senderDetails` within the configured window are rejected with `409 DUPLICATE_REQUEST`. Include a distinct `timestamp` per real payment.


## OpenAPI

````yaml POST /api/v1/transaction/pool-account
openapi: 3.1.0
info:
  title: Afriex Business API
  version: 1.0.8
  description: >-
    Welcome to the Afriex Business API. This API allows you to manage customers,
    process payments, handle payouts, and receive real-time notifications via
    webhooks.


    For detailed guidance on authentication, pagination, error handling, and
    webhooks, please refer to the [dedicated guides](https://docs.afriex.com) in
    the top bar. The guide provides a step-by-step instructions to help you
    integrate seamlessly.
  termsOfService: https://www.afriex.com/terms-and-condition
  contact:
    name: Afriex API Support
    email: support@afriex.com
    url: https://docs.afriex.com
  license:
    name: Proprietary
    url: https://www.afriex.com/terms-and-condition
servers:
  - url: https://sandbox.api.afriex.com
    description: Staging Base URL
  - url: https://api.afriex.com
    description: Production Base URL
security:
  - ApiKey: []
tags:
  - name: Customers
    description: Create and manage your customers.
  - name: Payment Methods
    description: Register and resolve customer payout and collection methods.
  - name: Transactions
    description: Create and track deposits, withdrawals, and swaps.
  - name: Balance
    description: View and top up your business wallet balances.
  - name: Rates
    description: Fetch real-time exchange rates.
  - name: Checkout Sessions
    description: Create hosted checkout sessions.
  - name: Webhooks
    description: Webhook event payloads and sandbox webhook testing.
  - name: Media
    description: Generate presigned URLs for secure file uploads.
paths:
  /api/v1/transaction/pool-account:
    parameters:
      - $ref: '#/components/parameters/x-api-signature'
      - $ref: '#/components/parameters/x-api-version'
    post:
      tags:
        - Transactions
      summary: Submit a pool-account payment proof
      description: >-
        Submits proof of a deposit made to the business pool account. The
        request creates a business deposit transaction in `IN_REVIEW` status; an
        operator confirms the bank inflow before the funds are credited. The
        response returns that transaction. Duplicate submissions of the same
        business, customer, amount, reference, timestamp and sender details
        within the configured idempotency window are rejected.
      operationId: submitPoolAccountPaymentProof
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PoolAccountPaymentProofRequest'
            examples:
              minimal:
                summary: Submit a pool-account proof of payment
                value:
                  amount: 5000
                  customerId: 6929843e2c4653277440acc0
                  countryCode: NG
                  reference: 6929843e2c4653277440acc0
                  fileKey: 64f0c2a1e4b0a1b2c3d4e5f6/proof.pdf
                  timestamp: '2026-01-01T12:00:00.000Z'
              withSenderDetails:
                summary: Submit a proof with sender details
                value:
                  amount: 5000
                  customerId: 6929843e2c4653277440acc0
                  countryCode: NG
                  reference: 6929843e2c4653277440acc0
                  fileKey: 64f0c2a1e4b0a1b2c3d4e5f6/proof.pdf
                  timestamp: '2026-01-01T12:00:00.000Z'
                  senderDetails:
                    name: John Doe
                    accountNumber: '0123456789'
                    bankName: GTBank
                    countryCode: NG
      responses:
        '201':
          description: Proof submitted successfully.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Transaction'
        '400':
          description: Invalid request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingRequiredField:
                  summary: Missing required field
                  value:
                    code: INVALID_BUSINESS_POOL_ACCOUNT_REQUEST
                    error: Invalid business pool account request
                    details:
                      errorMessage: Invalid business pool account request
                      friendlyMessage: No amount provided
        '401':
          description: Unauthorized - Invalid business API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingApiKey:
                  summary: Missing API key
                  value:
                    code: AUTHENTICATION_ERROR
                    error: Authorization header is missing
                    details: {}
                invalidApiKey:
                  summary: Invalid API key
                  value:
                    code: AUTHENTICATION_ERROR
                    error: Invalid authorization header
                    details: {}
        '409':
          description: Duplicate submission within the idempotency window.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                duplicateRequest:
                  summary: Duplicate submission within the idempotency window
                  value:
                    code: DUPLICATE_REQUEST
                    error: Duplicate request
                    details:
                      errorMessage: Duplicate request
                      friendlyMessage: ''
        '500':
          description: Server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                serverError:
                  summary: Unexpected server error
                  value:
                    code: INTERNAL_SERVER_ERROR
                    error: It's not you, it's us, please reach out to support
                    details: {}
      x-codeSamples:
        - lang: TypeScript
          label: Afriex SDK
          source: |
            await afriex.transactions.submitPoolAccountPaymentProof({
              amount: 5000,
              customerId: "customer-id",
              countryCode: "NG",
              reference: "pool-account-reference",
              fileKey: "s3-object-key",
              timestamp: "2026-01-01T12:00:00.000Z",
            });
components:
  parameters:
    x-api-signature:
      name: x-api-signature
      in: header
      required: false
      description: >-
        Signature of the request payload, used for request authentication where
        payload signing is enabled for your business.
      schema:
        type: string
    x-api-version:
      name: x-api-version
      in: header
      required: false
      description: >-
        API version in ISO 8601 format (e.g. 2025-12-28). Defaults to latest
        stable.
      schema:
        type: string
  schemas:
    PoolAccountPaymentProofRequest:
      type: object
      required:
        - amount
        - customerId
        - countryCode
        - reference
        - fileKey
        - timestamp
      properties:
        amount:
          type: number
          minimum: 0
          exclusiveMinimum: true
          description: The deposit amount in the major currency unit.
        customerId:
          type: string
          description: >-
            The Afriex customer ID the deposit should be credited to. Applies
            when `reference` is a customer reference, in which case it must
            match that customer. When `reference` is the business's own
            pool-account reference the deposit is credited to the business and
            this field is not used for routing.
        countryCode:
          type: string
          description: ISO 3166-1 alpha-2 country code of the pool account.
        reference:
          type: string
          description: >-
            The pool-account reference returned by `GET
            /api/v1/payment-method/pool-account`. Used to reconcile the deposit.
        fileKey:
          type: string
          description: >-
            The S3 object key of the uploaded proof-of-payment file. Obtain this
            from `POST /api/v1/media/url` with `type: transaction` first; a URL
            requested without that type uploads to a different bucket and the
            key will be rejected as not found.
        timestamp:
          type: string
          format: date-time
          description: >-
            ISO 8601 timestamp of when the payment was sent. Used for
            idempotency together with the other request fields.
        senderDetails:
          $ref: '#/components/schemas/PoolAccountPaymentProofSenderDetails'
    Transaction:
      type: object
      properties:
        transactionId:
          type: string
          description: The unique identifier for the transaction.
        customerId:
          type: string
          description: The unique identifier of the customer.
        sourceId:
          type: string
          description: The unique identifier of the source payment method.
        destinationId:
          type: string
          description: The unique identifier of the destination payment method.
        sourceAmount:
          type: string
          description: The souce transaction amount value
        sourceCurrency:
          type: string
          description: The currency code of the wallet charged.
        destinationAmount:
          type: string
          description: The destination transaction amount value
        destinationCurrency:
          type: string
          description: The description currency code.
        type:
          type: string
          enum:
            - DEPOSIT
            - WITHDRAW
            - SWAP
          description: The type of transaction.
        channel:
          type: string
          enum:
            - BANK_ACCOUNT
            - SWIFT
            - MOBILE_MONEY
            - UPI
            - INTERAC
            - WE_CHAT
            - CARD
            - CRYPTO
            - VIRTUAL_BANK_ACCOUNT
            - POOL_ACCOUNT
            - ACH_BANK_ACCOUNT
            - PAYBILL_TILL
            - RFP
            - VIRTUAL_CARD
            - ALIPAY
            - WALLET
          description: The payment channel of the transaction.
        status:
          type: string
          enum:
            - PENDING
            - PROCESSING
            - SUCCESS
            - FAILED
            - CANCELLED
            - REFUNDED
            - RETRY
            - UNKNOWN
            - SCHEDULED
            - CUSTOMER_ACTION_REQUIRED
            - REJECTED
            - IN_REVIEW
            - DISPUTED
            - DISPUTE_RESOLVED
            - DISPUTE_WON
            - DISPUTE_LOST
            - DISPUTE_EVIDENCE_SUBMITTED
          description: The current status of the transaction.
        merchantReference:
          type: string
          description: >-
            The merchant-supplied reference for the transaction (mirrors
            meta.reference from the create request).
        rate:
          type: string
          description: >-
            The realized source-to-destination exchange rate for the
            transaction, expressed as `1 sourceCurrency = rate
            destinationCurrency` (equal to destinationAmount / sourceAmount).
        fee:
          type: string
          description: >-
            The fee charged for this transaction, denominated in
            `sourceCurrency`. It is reported separately from `sourceAmount`.
            Omitted when no fee applied to the transaction.
        meta:
          type: object
          description: >-
            Transaction metadata. Echoes the metadata you attached on create and
            may include server-set state flags such as `otpRequired` and
            `failureReason`.
          properties:
            narration:
              type: string
              description: >-
                The narration you attached when creating the transaction, echoed
                back. An empty string when none was provided.
            otpRequired:
              type: boolean
              description: >-
                Returned on deposits that may need an extra authorization step.
                When `true`, the deposit is waiting for the customer to submit a
                one-time password; call `POST
                /transaction/{transactionId}/authorize` to complete it.
            failureReason:
              type: object
              description: >-
                Present only when `status` is `FAILED` or `REJECTED`. Carries a
                stable `AFX_*` code and a customer-safe message. Branch on
                `code` rather than the underlying rail so your integration stays
                stable across routing changes.
              required:
                - code
                - message
                - retryable
              properties:
                code:
                  type: string
                  description: >-
                    Stable `AFX_*` failure code. Safe to switch on; the set
                    grows over time but existing values do not change meaning.
                  example: AFX_VELOCITY_LIMIT_EXCEEDED
                  enum:
                    - AFX_REQUEST_FAILED
                    - AFX_SYSTEM_ERROR
                    - AFX_SERVICE_UNAVAILABLE
                    - AFX_INVALID_CURRENCY
                    - AFX_INVALID_AMOUNT
                    - AFX_INVALID_RECIPIENT
                    - AFX_RECIPIENT_NOT_FOUND
                    - AFX_BENEFICIARY_RESTRICTED
                    - AFX_INVALID_SENDER
                    - AFX_INVALID_REQUEST
                    - AFX_VELOCITY_LIMIT_EXCEEDED
                    - AFX_AMOUNT_LIMIT_EXCEEDED
                    - AFX_PAYMENT_FAILED
                    - AFX_COMPLIANCE_REJECTED
                    - AFX_PROPOSAL_EXPIRED
                message:
                  type: string
                  description: >-
                    Customer-safe short description of the failure. Suitable for
                    display; do not parse — branch on `code` instead.
                retryable:
                  type: boolean
                  description: >-
                    `true` when re-submitting the same request (or, for
                    `AFX_PROPOSAL_EXPIRED`, starting a fresh proposal) may
                    succeed. `false` when the caller must change the request
                    before retrying.
          additionalProperties: true
        createdAt:
          type: string
          description: The date and time the transaction was created.
        updatedAt:
          type: string
          description: The date and time the transaction was last updated.
    ErrorResponse:
      type: object
      properties:
        code:
          type: string
          description: Machine-readable error code.
        error:
          type: string
          description: Human-readable error message.
        details:
          $ref: '#/components/schemas/ErrorDetails'
    PoolAccountPaymentProofSenderDetails:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          description: The sender's full name.
        accountNumber:
          type: string
          description: The sender's account number or wallet identifier.
        bankName:
          type: string
          description: The sender's bank or financial institution.
        countryCode:
          type: string
          description: ISO 3166-1 alpha-2 country code for the sender.
    ErrorDetails:
      type: object
      properties:
        errorMessage:
          type: string
          description: Detailed/technical error message.
        friendlyMessage:
          type: string
          description: User-facing error message safe to display.
        data:
          type: object
          description: >-
            Optional caller-safe context for the error. On a customer-create
            uniqueness conflict (EMAIL_ALREADY_EXISTS /
            PHONE_NUMBER_ALREADY_EXISTS) this carries the existing customer's
            id, so you can adopt it without a follow-up lookup.
          properties:
            customerId:
              type: string
              description: Id of the existing customer (on a create conflict).
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Static business API key issued from the dashboard. A business can
        provision **multiple API keys**, each scoped to a configurable set of
        **permissions** (e.g. read transactions, create deposits, etc).
        Permissions are chosen per key at creation time in the dashboard and may
        be revoked by deleting the key. Requests made with a key that does not
        include the permission required by the target endpoint will be rejected
        with a `403 Forbidden` response; an unrecognised, malformed or revoked
        key returns `401 Unauthorized`. Manage your keys and their permissions
        under **Developer → API keys** in the dashboard.

````