Execute Payout
curl --request POST \
--url https://quickei.io/api/partner/sandbox/v1/payout \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"quote_id": "<string>",
"lookup_token": "<string>",
"amount": 123,
"sender_currency": "<string>",
"receiver_currency": "<string>",
"reference": "<string>",
"idempotency_key": "<string>",
"description": "<string>"
}
'import requests
url = "https://quickei.io/api/partner/sandbox/v1/payout"
payload = {
"quote_id": "<string>",
"lookup_token": "<string>",
"amount": 123,
"sender_currency": "<string>",
"receiver_currency": "<string>",
"reference": "<string>",
"idempotency_key": "<string>",
"description": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
quote_id: '<string>',
lookup_token: '<string>',
amount: 123,
sender_currency: '<string>',
receiver_currency: '<string>',
reference: '<string>',
idempotency_key: '<string>',
description: '<string>'
})
};
fetch('https://quickei.io/api/partner/sandbox/v1/payout', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://quickei.io/api/partner/sandbox/v1/payout",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'quote_id' => '<string>',
'lookup_token' => '<string>',
'amount' => 123,
'sender_currency' => '<string>',
'receiver_currency' => '<string>',
'reference' => '<string>',
'idempotency_key' => '<string>',
'description' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://quickei.io/api/partner/sandbox/v1/payout"
payload := strings.NewReader("{\n \"quote_id\": \"<string>\",\n \"lookup_token\": \"<string>\",\n \"amount\": 123,\n \"sender_currency\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"idempotency_key\": \"<string>\",\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://quickei.io/api/partner/sandbox/v1/payout")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"quote_id\": \"<string>\",\n \"lookup_token\": \"<string>\",\n \"amount\": 123,\n \"sender_currency\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"idempotency_key\": \"<string>\",\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://quickei.io/api/partner/sandbox/v1/payout")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"quote_id\": \"<string>\",\n \"lookup_token\": \"<string>\",\n \"amount\": 123,\n \"sender_currency\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"idempotency_key\": \"<string>\",\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"payout.payout_id": "<string>",
"payout.reference": "<string>",
"payout.amount": 123,
"payout.currency": "<string>",
"payout.fee": 123,
"payout.total_deducted": 123,
"payout.exchange_rate": 123,
"payout.receiver_amount": 123,
"payout.receiver_currency": "<string>",
"payout.status": "<string>",
"payout.trx_id": "<string>",
"payout.created_at": "<string>",
"payout.processed_at": "<string>"
}Partner API
Execute Payout
Send a payout to a Quickei user wallet
POST
/
api
/
partner
/
sandbox
/
v1
/
payout
Execute Payout
curl --request POST \
--url https://quickei.io/api/partner/sandbox/v1/payout \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"quote_id": "<string>",
"lookup_token": "<string>",
"amount": 123,
"sender_currency": "<string>",
"receiver_currency": "<string>",
"reference": "<string>",
"idempotency_key": "<string>",
"description": "<string>"
}
'import requests
url = "https://quickei.io/api/partner/sandbox/v1/payout"
payload = {
"quote_id": "<string>",
"lookup_token": "<string>",
"amount": 123,
"sender_currency": "<string>",
"receiver_currency": "<string>",
"reference": "<string>",
"idempotency_key": "<string>",
"description": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
quote_id: '<string>',
lookup_token: '<string>',
amount: 123,
sender_currency: '<string>',
receiver_currency: '<string>',
reference: '<string>',
idempotency_key: '<string>',
description: '<string>'
})
};
fetch('https://quickei.io/api/partner/sandbox/v1/payout', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://quickei.io/api/partner/sandbox/v1/payout",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'quote_id' => '<string>',
'lookup_token' => '<string>',
'amount' => 123,
'sender_currency' => '<string>',
'receiver_currency' => '<string>',
'reference' => '<string>',
'idempotency_key' => '<string>',
'description' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://quickei.io/api/partner/sandbox/v1/payout"
payload := strings.NewReader("{\n \"quote_id\": \"<string>\",\n \"lookup_token\": \"<string>\",\n \"amount\": 123,\n \"sender_currency\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"idempotency_key\": \"<string>\",\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://quickei.io/api/partner/sandbox/v1/payout")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"quote_id\": \"<string>\",\n \"lookup_token\": \"<string>\",\n \"amount\": 123,\n \"sender_currency\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"idempotency_key\": \"<string>\",\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://quickei.io/api/partner/sandbox/v1/payout")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"quote_id\": \"<string>\",\n \"lookup_token\": \"<string>\",\n \"amount\": 123,\n \"sender_currency\": \"<string>\",\n \"receiver_currency\": \"<string>\",\n \"reference\": \"<string>\",\n \"idempotency_key\": \"<string>\",\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"payout.payout_id": "<string>",
"payout.reference": "<string>",
"payout.amount": 123,
"payout.currency": "<string>",
"payout.fee": 123,
"payout.total_deducted": 123,
"payout.exchange_rate": 123,
"payout.receiver_amount": 123,
"payout.receiver_currency": "<string>",
"payout.status": "<string>",
"payout.trx_id": "<string>",
"payout.created_at": "<string>",
"payout.processed_at": "<string>"
}Execute a payout to credit a Quickei user’s wallet. Your merchant wallet is debited and the recipient’s wallet is credited instantly.
Success Response
Parameters
You can execute a payout in two ways: using aquote_id from a previous quote, or by providing the lookup and amount parameters directly.
string
The quote ID from the Quote endpoint. If provided, the payout uses the locked exchange rate and fees from the quote. When using
quote_id, you do not need to provide lookup_token, amount, sender_currency, or receiver_currency.string
The token from the Lookup endpoint identifying the recipient. Required if
quote_id is not provided.number
Amount to send from your merchant wallet. Must be greater than 0. Required if
quote_id is not provided.string
ISO 4217 currency code of your merchant wallet (e.g.
EUR). Max 10 characters. Required if quote_id is not provided.string
ISO 4217 currency code of the recipient’s wallet (e.g.
XAF). Max 10 characters. Required if quote_id is not provided.string
required
Your internal reference for this payout (max 255 characters). Must be unique per merchant account.
string
required
A unique key (max 64 characters) to prevent duplicate payouts. If a payout with the same key already exists, the original payout is returned.
string
Optional description visible in the transaction history (max 500 characters).
With Quote ID (Recommended)
Using aquote_id locks in the exchange rate and fees from the quote.
curl -X POST https://quickei.io/api/partner/sandbox/v1/payout \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"quote_id": "f7e6d5c4-b3a2-1098-7654-321fedcba098",
"reference": "PAYROLL-2026-03-001",
"idempotency_key": "payout_inv_2026_0042",
"description": "March 2026 salary"
}'
Without Quote ID (Direct)
If you skip the quote step, Quickei calculates the rate and fees at execution time.curl -X POST https://quickei.io/api/partner/sandbox/v1/payout \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"lookup_token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"amount": 100.00,
"sender_currency": "EUR",
"receiver_currency": "XAF",
"reference": "REM-78901",
"idempotency_key": "payout_inv_2026_0043",
"description": "Transfer from ExampleRemit"
}'
Success Response 200
{
"message": {
"success": ["Payout completed successfully."]
},
"data": {
"payout": {
"payout_id": "POAB1C2D3E",
"reference": "PAYROLL-2026-03-001",
"amount": 100.00,
"currency": "EUR",
"fee": 2.50,
"total_deducted": 102.50,
"exchange_rate": 655.957,
"receiver_amount": 65595.70,
"receiver_currency": "XAF",
"status": "completed",
"description": "March 2026 salary",
"trx_id": "PP8274619350",
"created_at": "2026-03-29T14:01:15+00:00",
"processed_at": "2026-03-29T14:01:15+00:00"
}
}
}
string
Unique payout identifier (format:
PO + 8 random alphanumeric characters). Use this to check status via GET /payout/{id}.string
Your internal reference as provided in the request.
number
The amount sent (before fees).
string
The sender currency code.
number
Total fee charged (fixed + percentage).
number
Total debited from your merchant wallet (
amount + fee).number
Applied exchange rate from sender to receiver currency.
number
Amount credited to the recipient’s wallet.
string
The recipient’s currency code.
string
Payout status:
completed, pending, or failed.string
Quickei internal transaction ID.
string
ISO 8601 timestamp when the payout was created.
string
ISO 8601 timestamp when the payout was processed.
null if still pending.Idempotency
Theidempotency_key prevents duplicate payouts. If you send the same key twice:
- The original payout is returned with
"duplicate": true - No additional funds are moved
- The response status is
200
{
"message": {
"success": ["Payout already processed."]
},
"data": {
"duplicate": true,
"payout": {
"payout_id": "POAB1C2D3E",
"reference": "PAYROLL-2026-03-001",
"amount": 100.00,
"currency": "EUR",
"fee": 2.50,
"total_deducted": 102.50,
"exchange_rate": 655.957,
"receiver_amount": 65595.70,
"receiver_currency": "XAF",
"status": "completed",
"description": "March 2026 salary",
"trx_id": "PP8274619350",
"created_at": "2026-03-29T14:01:15+00:00",
"processed_at": "2026-03-29T14:01:15+00:00"
}
}
}
Always include an
idempotency_key. Without it, the request will be rejected (it is required). The reference must also be unique per merchant account — a duplicate reference will be rejected even with a new idempotency key.Error Responses
| Status | Message | Cause |
|---|---|---|
400 | Invalid or expired quote. | The quote_id has expired (older than 5 minutes) or does not belong to your account |
400 | Invalid or expired lookup token. | The lookup_token has expired (older than 10 minutes) |
400 | Insufficient balance. | Merchant wallet balance is less than total_deducted |
400 | Currency EUR is not authorized for payouts. | Currency not enabled for payouts on your account |
400 | Amount exceeds per-transaction limit | Amount exceeds the per-transaction limit for this currency |
400 | Daily payout limit exceeded | Daily payout volume limit reached for this currency |
400 | Monthly payout limit exceeded | Monthly payout volume limit reached for this currency |
400 | Duplicate reference. | A different payout already uses this reference |
400 | Recipient not found or inactive. | The user account is deactivated |
400 | Recipient wallet not found for currency: XAF | Recipient has no wallet in the specified receiver currency |
422 | Validation error | Missing required fields |
401 | Invalid API credentials. | Bad or missing Bearer token |
What happens if a payout fails mid-execution?
What happens if a payout fails mid-execution?
Payouts are atomic. If any step fails (debit, credit, or ledger entry), the entire transaction is rolled back. Your merchant wallet is not debited and the recipient receives nothing. You can safely retry with the same
idempotency_key.
