curl --request POST \
--url https://sandbox-api.sakawave.example/v1/transfer-recipients \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"type": "individual",
"displayName": "Ada Okafor",
"firstName": "Ada",
"lastName": "Okafor",
"relationship": "vendor",
"email": "ada@example.com",
"phoneNumber": "+2348012345678",
"address": {
"line1": "14 Marina Road",
"city": "Lagos",
"stateOrProvince": "Lagos",
"postalCode": "100001",
"country": "NG"
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
type: 'individual',
displayName: 'Ada Okafor',
firstName: 'Ada',
lastName: 'Okafor',
relationship: 'vendor',
email: 'ada@example.com',
phoneNumber: '+2348012345678',
address: {
line1: '14 Marina Road',
city: 'Lagos',
stateOrProvince: 'Lagos',
postalCode: '100001',
country: 'NG'
}
})
};
fetch('https://sandbox-api.sakawave.example/v1/transfer-recipients', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://sandbox-api.sakawave.example/v1/transfer-recipients"
payload = {
"type": "individual",
"displayName": "Ada Okafor",
"firstName": "Ada",
"lastName": "Okafor",
"relationship": "vendor",
"email": "ada@example.com",
"phoneNumber": "+2348012345678",
"address": {
"line1": "14 Marina Road",
"city": "Lagos",
"stateOrProvince": "Lagos",
"postalCode": "100001",
"country": "NG"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "01K2Z3AB4G5H6J7K8MNPQRSTVW",
"type": "individual",
"displayName": "Ada Okafor",
"relationship": "vendor",
"email": "ada@example.com",
"phoneNumber": "+2348012345678",
"address": null,
"defaultPaymentDetailId": "01K2Z3AB4Q5R6S7T8VWXYZABCD",
"paymentDetails": [
{
"id": "01K2Z3AB4Q5R6S7T8VWXYZABCD",
"recipientId": "01K2Z3AB4G5H6J7K8MNPQRSTVW",
"routeId": "01K2Z3AB4M5N6P7Q8RSTVWXYZA",
"paymentMethod": "bank-transfer",
"currency": "KES",
"country": "KE",
"accountHolderName": "Ada Okafor",
"institutionName": "Example Bank",
"maskedIdentifier": "•••• 6789",
"isDefault": true,
"providerLocked": false,
"createdAt": "2026-08-14T09:06:00.000Z"
}
],
"createdAt": "2026-08-14T09:05:00.000Z"
}{
"statusCode": 400,
"message": "Must be a valid identifier.",
"code": "validation_failed",
"errors": [
{
"message": "Must be a valid identifier.",
"field": "accountId",
"code": "custom",
"path": [
"accountId"
]
}
]
}{
"statusCode": 401,
"code": "INVALID_API_KEY",
"message": "Invalid or inactive API credentials."
}{
"statusCode": 429,
"message": "Too many API requests. Try again later.",
"code": "api_key_rate_limit_exceeded",
"retryAfterSeconds": 17
}{
"statusCode": 500,
"code": "internal_server_error",
"message": "An unexpected error occurred."
}Create a transfer recipient
Creates a provider-neutral recipient identity — who you are paying, not how. Routing comes next, as one or more payment details. A recipient with no details cannot be paid.
curl --request POST \
--url https://sandbox-api.sakawave.example/v1/transfer-recipients \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"type": "individual",
"displayName": "Ada Okafor",
"firstName": "Ada",
"lastName": "Okafor",
"relationship": "vendor",
"email": "ada@example.com",
"phoneNumber": "+2348012345678",
"address": {
"line1": "14 Marina Road",
"city": "Lagos",
"stateOrProvince": "Lagos",
"postalCode": "100001",
"country": "NG"
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
type: 'individual',
displayName: 'Ada Okafor',
firstName: 'Ada',
lastName: 'Okafor',
relationship: 'vendor',
email: 'ada@example.com',
phoneNumber: '+2348012345678',
address: {
line1: '14 Marina Road',
city: 'Lagos',
stateOrProvince: 'Lagos',
postalCode: '100001',
country: 'NG'
}
})
};
fetch('https://sandbox-api.sakawave.example/v1/transfer-recipients', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://sandbox-api.sakawave.example/v1/transfer-recipients"
payload = {
"type": "individual",
"displayName": "Ada Okafor",
"firstName": "Ada",
"lastName": "Okafor",
"relationship": "vendor",
"email": "ada@example.com",
"phoneNumber": "+2348012345678",
"address": {
"line1": "14 Marina Road",
"city": "Lagos",
"stateOrProvince": "Lagos",
"postalCode": "100001",
"country": "NG"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"id": "01K2Z3AB4G5H6J7K8MNPQRSTVW",
"type": "individual",
"displayName": "Ada Okafor",
"relationship": "vendor",
"email": "ada@example.com",
"phoneNumber": "+2348012345678",
"address": null,
"defaultPaymentDetailId": "01K2Z3AB4Q5R6S7T8VWXYZABCD",
"paymentDetails": [
{
"id": "01K2Z3AB4Q5R6S7T8VWXYZABCD",
"recipientId": "01K2Z3AB4G5H6J7K8MNPQRSTVW",
"routeId": "01K2Z3AB4M5N6P7Q8RSTVWXYZA",
"paymentMethod": "bank-transfer",
"currency": "KES",
"country": "KE",
"accountHolderName": "Ada Okafor",
"institutionName": "Example Bank",
"maskedIdentifier": "•••• 6789",
"isDefault": true,
"providerLocked": false,
"createdAt": "2026-08-14T09:06:00.000Z"
}
],
"createdAt": "2026-08-14T09:05:00.000Z"
}{
"statusCode": 400,
"message": "Must be a valid identifier.",
"code": "validation_failed",
"errors": [
{
"message": "Must be a valid identifier.",
"field": "accountId",
"code": "custom",
"path": [
"accountId"
]
}
]
}{
"statusCode": 401,
"code": "INVALID_API_KEY",
"message": "Invalid or inactive API credentials."
}{
"statusCode": 429,
"message": "Too many API requests. Try again later.",
"code": "api_key_rate_limit_exceeded",
"retryAfterSeconds": 17
}{
"statusCode": 500,
"code": "internal_server_error",
"message": "An unexpected error occurred."
}More is required than looks likely
relationship, email, and a full address are required, because payout providers ask for them. Omitting them here is not a shortcut — it produces a recipient that cannot be turned into a destination, and the refusal arrives later as 422 recipient_profile_incomplete.
The name fields depend on type:
type | Also required |
|---|---|
individual | firstName and lastName |
business | legalName |
line2, both state and stateOrProvince are accepted, and line1 and city need at least two characters.Error codes
| Status | code | Cause |
|---|---|---|
400 | validation_failed | A field failed validation, an unknown field was sent, or the name fields do not match type. |
401 | INVALID_API_KEY | The key is missing, invalid, inactive, expired, from the other environment, or blocked by its IP allowlist. |
429 | api_key_rate_limit_exceeded | The per-minute limit for this key was exceeded. |
Authorizations
A secret API key, sent as Authorization: Bearer sk_test_… in sandbox or Bearer sk_live_… in live.
Body
Decides which name fields are required.
individual, business What you call this recipient. Shown on destinations and transfers.
2 - 200How this recipient relates to you, such as vendor or supplier. Required — payout providers ask for it.
2 - 80Required. Payout providers ask for it.
Show child attributes
Show child attributes
Required when type is individual.
100Required when type is individual.
100Required when type is business.
20024Response
Successful response.
A 26-character ULID.
26^[0-7][0-9A-HJKMNP-TV-Z]{25}$"01K2Z3AB4C5D6E7F8G9HJKMNPQ"
individual, business A 26-character ULID.
26^[0-7][0-9A-HJKMNP-TV-Z]{25}$"01K2Z3AB4C5D6E7F8G9HJKMNPQ"
Show child attributes
Show child attributes
"2026-08-14T09:00:00.000Z"