IRT

Create and fund a cross-border transaction

Changed on

Initiates a cross-border payout in a single call: resolves the merchant configuration, funds the transaction against the quote identified by rateId, reserves the float and dispatches the payout asynchronously. Returns synchronously with state pending. Replaying the same externalId returns the original transaction instead of creating a second payout. When duplicate protection is enforced for your account, the externalId is also your payout reference across every payout endpoint: a replay with the same payout details answers 200 with the X-Idempotent-Replay: true header and idempotentReplay: true in the body, and an externalId already used with different payout details, or held by a transfer, is refused with 409 duplicate_reference. An existing transaction with this externalId that does not itself hold your payout reference — one created before duplicate protection, for instance — is still returned whatever the details sent, even when a transfer holds the reference: 200 with the X-Idempotent-Replay: true header and idempotentReplay: true in the body when duplicate protection is enforced, 201 otherwise.

post/irt/v1/transactions

Request

  • The document declares no server URL.
  • Auth
    none declared. Required headers: ApiKey, MerchantId, Environment

Headers

ApiKeystring required

Your api key. To create a key, please get into our dashboard. If you don't have access to it, please reach the Support team.

MerchantIdstring required

Your merchant ID. This information is available in our dashboard. If you don't have access to it, please reach the Support team.

Environment'live' | 'sandbox' required

Allow you to choose between the sandbox mode to perform some tests or the live mode for real world transactions.

Request body

externalIdstring required

Merchant-owned idempotency key. Replaying a request with the same external_id returns the original transaction instead of creating a second payout. When duplicate protection is enforced for your account, it is also your payout reference across every payout endpoint: reusing it with different payout details, or when a transfer holds it, is refused with 409 duplicate_reference. An existing transaction with this external_id that does not itself hold your payout reference (one created before duplicate protection, for instance) is still returned whatever the details sent, even when a transfer holds the reference: 200 with the X-Idempotent-Replay header when duplicate protection is enforced, 201 otherwise.

rejectionIdstring

Confirms a payout refused with 409 possible_duplicate: the rejection_id of that response. Resend the refused payout unchanged, to the same endpoint and with the same reference (the externalId, for a cross-border transaction), before the response's expires_at. A rejection confirms one payout only: resending the confirmed payout again gets the idempotent replay, while an unknown or expired rejection, one replaced by a later refusal of its confirmation, one already used by another payout, or one that refused a different payout is answered 422 invalid_duplicate_confirmation. Ignored unless duplicate protection and near-duplicate protection are both enforced for your account.

senderIdstring required

Identifier of a registered sender belonging to this merchant. The sender must be approved.

rateIdstring uuid required

Identifier of the quote to fund at, as returned by POST /irt/v1/quote/calculate. The quote must not have expired and its rate must still be current, otherwise the request is rejected with 422 rate_expired. A quote is funded for the rail, the country and, on a mobile wallet, the operator it was quoted for: another recipient.rail is rejected with 422 quote_rail_mismatch, another recipient.countryCode with 422 quote_country_mismatch, another recipient.provider with 422 quote_provider_mismatch.

amountstring required

Amount to send, in the quote input currency, as an exact decimal string. Must match the amount the quote was issued for.

currencystring required

Input currency of the amount, ISO 4217. Must match the quote input currency.

descriptionstring

Free-text description carried on the transaction

Example request

{
  "externalId": "MTO-TX-00123",
  "rejectionId": "ndr_V1StGXR8_Z5jdHi6B-myT",
  "senderId": "snd_V1StGXR8Z5jdHi6BmyT",
  "rateId": "7e6c2c2e-2b1a-4f3c-9d7a-2c2e2b1a4f3c",
  "amount": "200",
  "currency": "EUR",
  "recipient": {
    "rail": "mobile_wallet",
    "firstName": "Aminata",
    "lastName": "Traoré",
    "countryCode": "SN",
    "provider": "orange",
    "phone": "+221771234567",
    "accountNumber": "SN0123456789",
    "bankCode": "SN_ECOBANK",
    "middleName": "Fatou",
    "address1": "12 rue de la Corniche",
    "city": "Dakar",
    "email": "aminata@example.com",
    "dateOfBirth": "1992-05-23",
    "idType": "passport"
  },
  "description": "Family support August"
}

Response

Idempotent replay. Duplicate protection is enforced for your account, and a payout with this reference and the same payout details already exists: it is returned as it is now, and nothing is created or charged. Only ever sent with the X-Idempotent-Replay: true header and the body field idempotentReplay: true, which is absent from a normal creation. The payout details compared are the destination type, country, beneficiary, operator, requested amount and currency; on IRT and cross-border routes, also the sender identity and, on cross-border, the rateId, unless the reference was recorded by an earlier version of this check, which compared neither; other names (recipient, bank, display name), descriptions and metadata are ignored. Also returned when duplicate protection is enforced, whatever the details sent and even when a transfer holds the reference, for an existing transaction with this externalId that does not itself hold your payout reference (one created before duplicate protection, for instance).

idstring required

Hub2 transaction identifier

externalIdstring required

Merchant-owned idempotency key echoed back

status'created' | 'pending' | 'compliance_review' | 'pending_manual' | 'successful' | 'failed' | 'cancelled' required

Current state. A successful create-and-fund returns pending: the float is reserved and the payout is on its way.

senderIdstring required

Registered sender the payout was initiated for

corridorstring required

Corridor the payout was priced on

rail'mobile_wallet' | 'bank_transfer' required

Last-mile rail

inputCurrencystring required

Input currency, ISO 4217

inputAmountstring required

Amount sent, exact decimal string. This is the amount converted and paid out — the Hub2 fee is charged on top of it, so the float is debited inputAmount plus hub2Fee.

outputCurrencystring required

Output currency, ISO 4217

outputAmountstring required

Amount the recipient receives, frozen at funding. Priced on the full inputAmount — the Hub2 fee is additive and never reduces it.

hub2Feestring required

Total Hub2 fee applied, frozen at funding. The sum of the fees lines. Charged in addition to inputAmount, not deducted from it.

hub2Ratestring required

Exchange rate applied, frozen at funding and never recalculated

descriptionstring

Free-text description carried on the transaction

createdAtstring required

Creation timestamp, ISO 8601

updatedAtstring required

Timestamp of the last state change, ISO 8601. Equal to "createdAt" until the transaction first moves, so a lookup can tell a payout still awaiting its partner from one that settled without a webhook arriving.

idempotentReplaytrue

Present, and true, only when the response replays an existing payout (idempotent replay, HTTP 200 with the X-Idempotent-Replay: true header). Absent when the transaction has just been created.

Example response

{
  "id": "cbt_V1StGXR8Z5jdHi6BmyT",
  "externalId": "MTO-TX-00123",
  "status": "pending",
  "senderId": "snd_V1StGXR8Z5jdHi6BmyT",
  "corridor": "XOF_MOBILE_SENEGAL",
  "rail": "mobile_wallet",
  "inputCurrency": "EUR",
  "inputAmount": "200",
  "outputCurrency": "XOF",
  "outputAmount": "129223",
  "hub2Fee": "10.00",
  "fees": [
    {
      "id": "fee_V1StGXR8Z5jdHi6BmyT",
      "rate": "5.00",
      "type": "percent",
      "amount": "10.00",
      "currency": "EUR",
      "taxes": [
        {
          "id": "tax_V1StGXR8Z5jdHi6BmyT",
          "taxType": "tva",
          "type": "percent",
          "value": "18.00"
        }
      ]
    }
  ],
  "hub2Rate": "646.1176450000",
  "failureCause": {
    "code": "insufficient_funds"
  },
  "duplicateConfirmation": {
    "rejectionId": "ndr_V1StGXR8_Z5jdHi6B-myT"
  },
  "idempotentReplay": true
}

Changes