curl --request POST \
--url https://api.bachs.io/v1/payouts/destinations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "My GTBank Savings",
"currency": "NGN",
"label": "Treasury NGN Account",
"account_number": "0123456789",
"bank_code": "058"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'My GTBank Savings',
currency: 'NGN',
label: 'Treasury NGN Account',
account_number: '0123456789',
bank_code: '058'
})
};
fetch('https://api.bachs.io/v1/payouts/destinations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.bachs.io/v1/payouts/destinations"
payload = {
"name": "My GTBank Savings",
"currency": "NGN",
"label": "Treasury NGN Account",
"account_number": "0123456789",
"bank_code": "058"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.bachs.io/v1/payouts/destinations"
payload := strings.NewReader("{\n \"name\": \"My GTBank Savings\",\n \"currency\": \"NGN\",\n \"label\": \"Treasury NGN Account\",\n \"account_number\": \"0123456789\",\n \"bank_code\": \"058\"\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))
}{
"id": "pd_7Kq2mNv4XbR9dLc0",
"name": "My GTBank Savings",
"type": "bank_account",
"currency": "NGN",
"status": "pending_review",
"status_reason": null,
"is_usable": false,
"is_default": false,
"account_number": "0123456789",
"account_name": "JOHN DOE",
"bank_code": "058",
"bank_name": "Guaranty Trust Bank",
"phone_number": null,
"mobile_provider": null,
"wallet_address": null,
"network": null,
"reviewed_at": null,
"created_at": "2026-01-24T14:30:00.000Z",
"updated_at": "2026-01-24T14:30:00.000Z"
}{
"detail": "Invalid request parameters",
"error_code": "VALIDATION_ERROR",
"errors": [
{
"field": "amount",
"message": "Amount must be a positive decimal string",
"type": "value_error"
}
]
}{
"detail": "Invalid API key",
"error_code": "UNAUTHORIZED"
}{
"detail": "API key does not have permission for this operation",
"error_code": "FORBIDDEN"
}{
"detail": "Resource not found",
"error_code": "NOT_FOUND"
}{
"detail": "Rate limit exceeded. Please retry after a few seconds.",
"error_code": "TOO_MANY_REQUESTS"
}{
"detail": "An unexpected error occurred. Please try again later.",
"error_code": "INTERNAL_SERVER_ERROR"
}Create Payout Destination
Add a new payout destination (bank account, mobile money, or crypto wallet) where you can withdraw funds.
curl --request POST \
--url https://api.bachs.io/v1/payouts/destinations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "My GTBank Savings",
"currency": "NGN",
"label": "Treasury NGN Account",
"account_number": "0123456789",
"bank_code": "058"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'My GTBank Savings',
currency: 'NGN',
label: 'Treasury NGN Account',
account_number: '0123456789',
bank_code: '058'
})
};
fetch('https://api.bachs.io/v1/payouts/destinations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.bachs.io/v1/payouts/destinations"
payload = {
"name": "My GTBank Savings",
"currency": "NGN",
"label": "Treasury NGN Account",
"account_number": "0123456789",
"bank_code": "058"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.bachs.io/v1/payouts/destinations"
payload := strings.NewReader("{\n \"name\": \"My GTBank Savings\",\n \"currency\": \"NGN\",\n \"label\": \"Treasury NGN Account\",\n \"account_number\": \"0123456789\",\n \"bank_code\": \"058\"\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))
}{
"id": "pd_7Kq2mNv4XbR9dLc0",
"name": "My GTBank Savings",
"type": "bank_account",
"currency": "NGN",
"status": "pending_review",
"status_reason": null,
"is_usable": false,
"is_default": false,
"account_number": "0123456789",
"account_name": "JOHN DOE",
"bank_code": "058",
"bank_name": "Guaranty Trust Bank",
"phone_number": null,
"mobile_provider": null,
"wallet_address": null,
"network": null,
"reviewed_at": null,
"created_at": "2026-01-24T14:30:00.000Z",
"updated_at": "2026-01-24T14:30:00.000Z"
}{
"detail": "Invalid request parameters",
"error_code": "VALIDATION_ERROR",
"errors": [
{
"field": "amount",
"message": "Amount must be a positive decimal string",
"type": "value_error"
}
]
}{
"detail": "Invalid API key",
"error_code": "UNAUTHORIZED"
}{
"detail": "API key does not have permission for this operation",
"error_code": "FORBIDDEN"
}{
"detail": "Resource not found",
"error_code": "NOT_FOUND"
}{
"detail": "Rate limit exceeded. Please retry after a few seconds.",
"error_code": "TOO_MANY_REQUESTS"
}{
"detail": "An unexpected error occurred. Please try again later.",
"error_code": "INTERNAL_SERVER_ERROR"
}Authorizations
Bearer token authentication. Pass your API key as Authorization: Bearer sk_.... See Authentication for keys, scopes, and sandbox vs production.
Body
Register where money should land. Accepts both the field names this surface has always used and newer aliases, so a caller never has to know which generation of the API it is talking to. Where a legacy name and its alias overlap, the newer name wins.
Currency code this destination accepts (e.g., 'NGN', 'USD', 'USDT_TRC20').
10"NGN"
User-friendly name for this destination.
255"My GTBank Savings"
Alias for name. name wins if both are sent.
255null
Type of payout destination: bank_account, mobile_money, or crypto_wallet. Inferred from currency when omitted.
"bank_account"
Alias for type. type wins if both are sent.
null
Bank account number. Required for bank_account destinations.
50"0123456789"
Bank code or routing number. Required for bank_account destinations.
20"058"
Accepted for compatibility and ignored, because the account holder name is always resolved from the bank.
255null
Accepted for compatibility and ignored, because the bank name is always resolved from the bank.
255null
Phone number for the mobile money account. Required for mobile_money destinations.
20null
Mobile money provider (e.g., 'MTN', 'Vodafone'). Required for mobile_money destinations.
50null
Cryptocurrency wallet address. Required for crypto_wallet destinations.
255null
Blockchain network. Optional when the currency already names its network (e.g. USDT_TRC20).
50null
Additional custom metadata to associate with this destination.
null
Response
Success
Response containing payout destination details (bank account, mobile money, or crypto wallet).
Unique identifier for this payout destination. Use this ID when creating payouts.
"pd_7Kq2mNv4XbR9dLc0"
User-friendly name for this destination. Helps you identify destinations in your system.
"My GTBank Savings"
Type of payout destination: bank_account, mobile_money, or crypto_wallet. Determines which fields are populated.
bank_account, mobile_money, crypto_wallet "bank_account"
Currency code this destination accepts (e.g., 'NGN', 'USD', 'USDT_TRC20'). Payouts to this destination must use this currency.
"NGN"
Review status. pending_review: awaiting review, not usable yet. approved: cleared for payouts. rejected: permanently unusable, register a new destination instead.
pending_review, approved, rejected "approved"
Free-text reason set by review, populated when the destination is rejected. Null while pending or approved.
null
Whether this destination can be used for a payout right now. True only when status is approved and the destination has not been deactivated.
true
Whether a payout schedule pays out to this destination for its currency. Set it with PATCH /v1/payouts/destinations/{destination_id}.
false
Bank account number. Only populated for bank_account destinations.
"0123456789"
Account holder name as resolved from the bank. Only populated for bank_account destinations.
"JOHN DOE"
Bank code or routing number. Only populated for bank_account destinations.
"058"
Full name of the bank. Only populated for bank_account destinations.
"Guaranty Trust Bank"
Phone number associated with the mobile money account. Only populated for mobile_money destinations.
null
Mobile money provider (e.g., 'MTN', 'Vodafone'). Only populated for mobile_money destinations.
null
Cryptocurrency wallet address. Only populated for crypto_wallet destinations.
null
Blockchain network (e.g., 'TRC20', 'ERC20'). Only populated for crypto_wallet destinations. May be included in currency code (e.g., 'USDT_TRC20').
null
ISO 8601 timestamp when this destination was last reviewed by an admin. Null until reviewed.
null
ISO 8601 timestamp when this destination was created.
"2026-01-24T14:30:00.000Z"
ISO 8601 timestamp when this destination was last updated.
"2026-01-24T14:30:00.000Z"

