---
title: "Submit a pool-account payment proof"
method: POST
path: "/api/v1/transaction/pool-account"
tags: ["Transactions"]
---

# Submit a pool-account payment proof

`POST /api/v1/transaction/pool-account`

## Request

- Base URL: `https://sandbox.api.afriex.com`
- URL: `https://sandbox.api.afriex.com/api/v1/transaction/pool-account`
- Auth: API key in header `x-api-key`
- TypeScript: <https://skmtc.dev/afriex/apis/afriex-business-api/docs/api/v1/transaction/pool-account/post.ts> (a function with typed inputs; its response is checked against the schema)

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. The `timestamp` cannot be in the future. Your business must have a webhook URL set, otherwise the request is rejected with a 400.

## Request body

- PoolAccountPaymentProofRequest
  - `amount` number, required: The deposit amount in the major currency unit.
  - `customerId` string, required: 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` string, required: ISO 3166-1 alpha-2 country code of the pool account.
  - `reference` string, required: The pool-account reference returned by `GET /api/v1/payment-method/pool-account`. Used to reconcile the deposit.
  - `fileKey` string, required: 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` string, date-time, required: ISO 8601 timestamp of when the payment was sent. It cannot be in the future (a few minutes of clock difference is tolerated). Used for idempotency together with the other request fields.
  - `senderDetails` PoolAccountPaymentProofSenderDetails
    - `name` string, required: The sender's full name.
    - `accountNumber` string: The sender's account number or wallet identifier.
    - `bankName` string: The sender's bank or financial institution.
    - `countryCode` string: ISO 3166-1 alpha-2 country code for the sender.

## Response `201`

Proof submitted successfully.

- object
  - `data` Transaction
    - `transactionId` string: The unique identifier for the transaction.
    - `customerId` string: The unique identifier of the customer.
    - `sourceId` string: The unique identifier of the source payment method.
    - `destinationId` string: The unique identifier of the destination payment method.
    - `sourceAmount` string: The souce transaction amount value
    - `sourceCurrency` string: The currency code of the wallet charged.
    - `destinationAmount` string: The destination transaction amount value
    - `destinationCurrency` string: The description currency code.
    - `type` 'DEPOSIT' | 'WITHDRAW' | 'SWAP' | 'REVERSAL' | 'SCHEDULED' | 'SEND': The type of transaction. You can create `DEPOSIT`, `WITHDRAW` and `SWAP`; the other values can appear on transactions listed or fetched for your business.
    - `channel` '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' | 'PAYMENT_LINQ' | 'ADMIN': The payment channel of the transaction. `ADMIN` marks an adjustment Afriex made to your wallet; `PAYMENT_LINQ` a payment made through a payment link.
    - `status` 'PENDING' | 'PROCESSING' | 'SUCCESS' | 'FAILED' | 'CANCELLED' | 'REFUNDED' | 'RETRY' | 'UNKNOWN' | 'SCHEDULED' | 'CUSTOMER_ACTION_REQUIRED' | 'REJECTED' | 'IN_REVIEW' | 'RFI_REQUESTED' | 'DISPUTED' | 'DISPUTE_RESOLVED' | 'DISPUTE_WON' | 'DISPUTE_LOST' | 'DISPUTE_EVIDENCE_SUBMITTED': The current status of the transaction. `IN_REVIEW` and `RFI_REQUESTED` are review states: the transaction is still in flight and is waiting on a review, not on you. Treat them as non-terminal and keep polling or listening for `TRANSACTION.UPDATED`. `RFI_REQUESTED` may result in someone contacting you for more information about the transfer.
    - `merchantReference` string: The merchant-supplied reference for the transaction (mirrors meta.reference from the create request).
    - `rate` string: The realized source-to-destination exchange rate for the transaction, expressed as `1 sourceCurrency = rate destinationCurrency` (equal to destinationAmount / sourceAmount).
    - `fee` string: The fee charged for this transaction, denominated in `sourceCurrency`. It is reported separately from `sourceAmount`. Omitted when no fee applied to the transaction.
    - `meta` object: Transaction metadata. Echoes the metadata you attached on create and may include server-set state flags such as `otpRequired` and `failureReason`.
      - `narration` string: The narration you attached when creating the transaction, echoed back. An empty string when none was provided.
      - `otpRequired` boolean: 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` object: 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.
        - `code` 'AFX_REQUEST_FAILED' | 'AFX_SYSTEM_ERROR' | 'AFX_SERVICE_UNAVAILABLE' | 'AFX_INVALID_CURRENCY' | 'AFX_INVALID_AMOUNT' | 'AFX_INVALID_RECIPIENT' | 'AFX_RECIPIENT_NOT_FOUND' | 'AFX_ACCOUNT_CLOSED' | 'AFX_NAME_MISMATCH' | 'AFX_BENEFICIARY_RESTRICTED' | 'AFX_INVALID_SENDER' | 'AFX_INVALID_REQUEST' | 'AFX_VELOCITY_LIMIT_EXCEEDED' | 'AFX_AMOUNT_LIMIT_EXCEEDED' | 'AFX_RECIPIENT_WALLET_LIMIT_REACHED' | 'AFX_PAYMENT_FAILED' | 'AFX_COMPLIANCE_REJECTED' | 'AFX_PROPOSAL_EXPIRED', required: Stable `AFX_*` failure code. Safe to switch on; the set grows over time but existing values do not change meaning.
        - `message` string, required: Customer-safe short description of the failure. Suitable for display; do not parse it. Branch on `code` instead.
        - `retryable` boolean, required: `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.
    - `createdAt` string: The date and time the transaction was created.
    - `updatedAt` string: The date and time the transaction was last updated.

## Other responses

- `400`: Invalid request, or your business is not yet allowed to use the API: no webhook URL is set, the request IP is not on your whitelist, the business is not approved or is deactivated, or business verification (KYB) is required.
- `401`: Unauthorized - Invalid business API key.
- `409`: Duplicate submission within the idempotency window.
- `500`: Server error.
- `503`: Temporarily unavailable: an upstream service failed or timed out, or the API is momentarily offline. Retry with backoff and honour the Retry-After header when present.

---

[API](https://skmtc.dev/afriex/apis/afriex-business-api.md) - [All operations](https://skmtc.dev/afriex/apis/afriex-business-api/llms.txt) - [OpenAPI document](https://skmtc.dev/afriex/apis/afriex-business-api/revisions/d94198b6c256?raw)
