---
title: "Create a new transaction"
method: POST
path: "/api/v1/transaction"
tags: ["Transactions"]
---

# Create a new transaction

`POST /api/v1/transaction`

## Request

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

Create a new transaction to process a payment for a customer. Use `type: WITHDRAW` to send funds to a destination payment method (requires `destinationId`), `type: DEPOSIT` to pull funds from a source payment method (requires `sourceId`), or `type: SWAP` to convert funds between currencies within the Afriex wallet (requires `sourceCurrency`, `destinationCurrency`, `meta`, and exactly one of `sourceAmount` or `destinationAmount`). A DEPOSIT settles in one currency, so `sourceCurrency` and `destinationCurrency` must be the same. Card deposits cannot be created through the API. Your business must have a webhook URL set, otherwise the request is rejected with a 400.

## Request body

- union
  - object: Send funds to a customer's destination payment method. This is the default when type is omitted. Provide sourceAmount, destinationAmount or both; sending sourceAmount alone lets the API compute the destination side at the live forward rate.
    - `customerId` string, required: The unique identifier of the customer. Required for DEPOSIT and WITHDRAW transactions. Not required for SWAP, if omitted, the transaction runs against the business wallet.
    - `type` 'WITHDRAW': The type of transaction. DEPOSIT pulls funds from the customer's source payment method (requires sourceId). WITHDRAW sends funds to the customer's destination payment method (requires destinationId). SWAP converts funds between currencies within the Afriex wallet (requires sourceCurrency, destinationCurrency, meta, and exactly one of sourceAmount or destinationAmount; the API computes the other side at the live exchange rate, and sending both is rejected). If omitted, defaults to WITHDRAW.
    - `sourceAmount` union: A monetary amount. Accepts a number or a numeric string; responses return amounts as strings. Must be greater than zero.
      - number
      - string
    - `destinationAmount` union: A monetary amount. Accepts a number or a numeric string; responses return amounts as strings. Must be greater than zero.
      - number
      - string
    - `destinationCurrency` string, required: The 3-letter ISO 4217 currency code of the destination currency (e.g., USD, NGN). Upper case, and a currency Afriex supports.
    - `sourceCurrency` string, required: The 3-letter ISO 4217 currency code of the source currency (e.g., USD, NGN). Upper case, and a currency Afriex supports.
    - `destinationId` string, required: Required for WITHDRAW transactions. The id of the destination payment method that money will be sent to.
    - `sourceId` string: Required for DEPOSIT transactions. The id of the source payment method that money will be pulled from.
    - `meta` TransactionMeta, required
      - `narration` string: The optional reason for the transaction.
      - `invoice` string: The invoice filename (S3 object key) for the transaction, as returned by the media upload endpoint. Required for SWIFT withdrawals: the referenced object is verified to exist in storage before the transaction is created, so upload the file first and pass the returned key verbatim.
      - `idempotencyKey` string, required: The idempotency key for the transaction.
      - `reference` string, required: The reference for the transaction.
      - `settlement` 'spot' | 'request': Optional settlement handling for the transaction. `spot` (the default) processes immediately and debits your Payout wallet. `request` is only supported for WITHDRAW transactions: it debits your Collection wallet (rather than the default Payout wallet) and queues the payout for the next business day in the destination payment method's country. Omit `settlement` (or send `spot`) for an ordinary payout from the Payout wallet.
    - `shouldPreferSourceAmount` boolean: Opt in to deriving destinationAmount from sourceAmount even when both amounts are sent. Defaults to false, which keeps destination-wins semantics so a caller that echoes both amounts still gets the destinationAmount they asked for. Set true to have sourceAmount drive the payout via the forward rate.
    - `correspondentBankName` string: The correspondent (intermediary) bank name for USD payouts (WITHDRAW with destinationCurrency USD and meta.settlement 'request'). Only used as a fallback when the destination payment method lacks it. The payment method's value takes precedence. Must be provided together with correspondentBankAccountNumber.
    - `correspondentBankAccountNumber` string: The correspondent (intermediary) bank account number for USD payouts (WITHDRAW with destinationCurrency USD and meta.settlement 'request'). Only used as a fallback when the destination payment method lacks it. The payment method's value takes precedence. Must be provided together with correspondentBankName.
  - object: Pull funds from a customer's source payment method. Provide sourceAmount, destinationAmount or both. sourceCurrency and destinationCurrency must be the same currency; a mismatch is rejected.
    - `customerId` string, required: The unique identifier of the customer. Required for DEPOSIT and WITHDRAW transactions. Not required for SWAP, if omitted, the transaction runs against the business wallet.
    - `type` 'DEPOSIT', required: The type of transaction. DEPOSIT pulls funds from the customer's source payment method (requires sourceId). WITHDRAW sends funds to the customer's destination payment method (requires destinationId). SWAP converts funds between currencies within the Afriex wallet (requires sourceCurrency, destinationCurrency, meta, and exactly one of sourceAmount or destinationAmount; the API computes the other side at the live exchange rate, and sending both is rejected). If omitted, defaults to WITHDRAW.
    - `sourceAmount` union: A monetary amount. Accepts a number or a numeric string; responses return amounts as strings. Must be greater than zero.
      - number
      - string
    - `destinationAmount` union: A monetary amount. Accepts a number or a numeric string; responses return amounts as strings. Must be greater than zero.
      - number
      - string
    - `destinationCurrency` string, required: The 3-letter ISO 4217 currency code of the destination currency (e.g., USD, NGN). Upper case, and a currency Afriex supports.
    - `sourceCurrency` string, required: The 3-letter ISO 4217 currency code of the source currency (e.g., USD, NGN). Upper case, and a currency Afriex supports.
    - `destinationId` string: Required for WITHDRAW transactions. The id of the destination payment method that money will be sent to.
    - `sourceId` string, required: Required for DEPOSIT transactions. The id of the source payment method that money will be pulled from.
    - `meta` TransactionMeta, required
      - `narration` string: The optional reason for the transaction.
      - `invoice` string: The invoice filename (S3 object key) for the transaction, as returned by the media upload endpoint. Required for SWIFT withdrawals: the referenced object is verified to exist in storage before the transaction is created, so upload the file first and pass the returned key verbatim.
      - `idempotencyKey` string, required: The idempotency key for the transaction.
      - `reference` string, required: The reference for the transaction.
      - `settlement` 'spot' | 'request': Optional settlement handling for the transaction. `spot` (the default) processes immediately and debits your Payout wallet. `request` is only supported for WITHDRAW transactions: it debits your Collection wallet (rather than the default Payout wallet) and queues the payout for the next business day in the destination payment method's country. Omit `settlement` (or send `spot`) for an ordinary payout from the Payout wallet.
    - `shouldPreferSourceAmount` boolean: Opt in to deriving destinationAmount from sourceAmount even when both amounts are sent. Defaults to false, which keeps destination-wins semantics so a caller that echoes both amounts still gets the destinationAmount they asked for. Set true to have sourceAmount drive the payout via the forward rate.
    - `correspondentBankName` string: The correspondent (intermediary) bank name for USD payouts (WITHDRAW with destinationCurrency USD and meta.settlement 'request'). Only used as a fallback when the destination payment method lacks it. The payment method's value takes precedence. Must be provided together with correspondentBankAccountNumber.
    - `correspondentBankAccountNumber` string: The correspondent (intermediary) bank account number for USD payouts (WITHDRAW with destinationCurrency USD and meta.settlement 'request'). Only used as a fallback when the destination payment method lacks it. The payment method's value takes precedence. Must be provided together with correspondentBankName.
  - object: Convert funds between currencies within the Afriex wallet. Provide exactly one of sourceAmount or destinationAmount; sending both is rejected.
    - `customerId` string: The unique identifier of the customer. Required for DEPOSIT and WITHDRAW transactions. Not required for SWAP, if omitted, the transaction runs against the business wallet.
    - `type` 'SWAP', required: The type of transaction. DEPOSIT pulls funds from the customer's source payment method (requires sourceId). WITHDRAW sends funds to the customer's destination payment method (requires destinationId). SWAP converts funds between currencies within the Afriex wallet (requires sourceCurrency, destinationCurrency, meta, and exactly one of sourceAmount or destinationAmount; the API computes the other side at the live exchange rate, and sending both is rejected). If omitted, defaults to WITHDRAW.
    - `sourceAmount` union: A monetary amount. Accepts a number or a numeric string; responses return amounts as strings. Must be greater than zero.
      - number
      - string
    - `destinationAmount` union: A monetary amount. Accepts a number or a numeric string; responses return amounts as strings. Must be greater than zero.
      - number
      - string
    - `destinationCurrency` string, required: The 3-letter ISO 4217 currency code of the destination currency (e.g., USD, NGN). Upper case, and a currency Afriex supports.
    - `sourceCurrency` string, required: The 3-letter ISO 4217 currency code of the source currency (e.g., USD, NGN). Upper case, and a currency Afriex supports.
    - `destinationId` string: Required for WITHDRAW transactions. The id of the destination payment method that money will be sent to.
    - `sourceId` string: Required for DEPOSIT transactions. The id of the source payment method that money will be pulled from.
    - `meta` TransactionMeta, required
      - `narration` string: The optional reason for the transaction.
      - `invoice` string: The invoice filename (S3 object key) for the transaction, as returned by the media upload endpoint. Required for SWIFT withdrawals: the referenced object is verified to exist in storage before the transaction is created, so upload the file first and pass the returned key verbatim.
      - `idempotencyKey` string, required: The idempotency key for the transaction.
      - `reference` string, required: The reference for the transaction.
      - `settlement` 'spot' | 'request': Optional settlement handling for the transaction. `spot` (the default) processes immediately and debits your Payout wallet. `request` is only supported for WITHDRAW transactions: it debits your Collection wallet (rather than the default Payout wallet) and queues the payout for the next business day in the destination payment method's country. Omit `settlement` (or send `spot`) for an ordinary payout from the Payout wallet.
    - `shouldPreferSourceAmount` boolean: Opt in to deriving destinationAmount from sourceAmount even when both amounts are sent. Defaults to false, which keeps destination-wins semantics so a caller that echoes both amounts still gets the destinationAmount they asked for. Set true to have sourceAmount drive the payout via the forward rate.
    - `correspondentBankName` string: The correspondent (intermediary) bank name for USD payouts (WITHDRAW with destinationCurrency USD and meta.settlement 'request'). Only used as a fallback when the destination payment method lacks it. The payment method's value takes precedence. Must be provided together with correspondentBankAccountNumber.
    - `correspondentBankAccountNumber` string: The correspondent (intermediary) bank account number for USD payouts (WITHDRAW with destinationCurrency USD and meta.settlement 'request'). Only used as a fallback when the destination payment method lacks it. The payment method's value takes precedence. Must be provided together with correspondentBankName.

## Response `201`

Transaction created 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, business verification (KYB) is required, or the transaction is below the minimum that one of your business limits allows. `details.friendlyMessage` says which.
- `401`: Unauthorized.
- `402`: Your wallet balance is too low to cover the transaction. Fund the wallet and send the request again.
- `403`: The transaction is refused: it would take your business over one of its limits, the customer or business is not verified, the payment method is not active, or withdrawals are suspended for your business. For a limit, `details.friendlyMessage` gives the limit and its period, and for a daily, weekly or monthly amount limit how much is left.
- `404`: Not found.
- `409`: A transaction with the same `meta.idempotencyKey` or `meta.reference` already exists, or is still being processed. Nothing is charged twice; look up the original with GET /api/v1/transaction.
- `422`: The transaction cannot be created: the payment method's currency does not match `destinationCurrency`, or the destination country is not currently available. `details.friendlyMessage` carries the specific error.
- `429`: More than 60 transaction create requests from your business in the last 60 seconds. Rejected requests count toward the limit, so wait and retry with backoff, reusing the same `meta.idempotencyKey` so a retry cannot create a duplicate.
- `451`: The destination country or channel is blocked and cannot be used.
- `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)
