Avoid a payout pause for sender details
Send a real person's name, date of birth and address with a business's payouts, and resume a transfer that paused for sender details.
This recipe sends a real person's name, date of birth and address with a business's payouts, and resumes a transfer that paused for sender details.
Who it is for. Adire Logistics, the business from Onboard a business and its owners, which pays a supplier in Ghana 250.00 USD. It is also for any business whose older customers have no date of birth or address.
Status. Available. Only some payout routes need sender details. The API has no call that lists those routes in advance, so always send the details.
Money example
- Adire sends 250.00 USD to a Ghana mobile-money payee. The bank that pays out on that route must name a real person as the sender: first and last name, date of birth, email, street address and country.
- Adire is a company, so its profile has a business name but no person's name or date of birth. Gravv creates the transfer paused, instead of sending it and having the bank refuse it. Gravv charges your fee now, as for any transfer, and pays nothing out yet.
- You resume with the director's name and date of birth. Gravv pays out the 250.00 USD and charges no second fee.
- If you never resume, the pause expires after 72 hours by default (
expires_atis exact). The transfer fails withreasonsender_details_expired, and Gravv refunds the fee.
Before you start
- The customer you send the transfer for (
customer_id), and a funded source account. - For a business, the name, date of birth, country and address of a director or authorized signatory, such as the associated person you created.
- An email on the customer's profile. Gravv reads the email only from the profile.
Find out what is required
The paused response lists one requirements[] entry per missing detail. Its type is the exact additional_information field to send:
requirements[].type |
What to send |
|---|---|
remitter_full_name |
First and last name, such as "Tunde Bakare". Gravv splits it at the first space, so one word still counts as missing |
remitter_date_of_birth |
"1984-07-22" |
remitter_address |
The whole object: address_line1, city, postal_code, country and state |
remitter_country |
An ISO code, such as "NG" |
customer_email |
This is not a body field. Add email to the customer with PUT /v1/customers/{customer_id}, then resume with {} |
Gravv reads each detail first from your additional_information. For anything not sent there, Gravv reads the customer's profile.
Steps
Avoid the pause
Individual customers that you create through the API today already have a name, date of birth, email and address, so their payouts do not pause for sender details. A business customer's payouts do, so send a real person's details with every payout.
curl --request POST \
--url https://api.gravv.xyz/v1/transfer \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: 47e3da9e-3600-41b1-90a2-9cc43beeb744' \
--header 'Content-Type: application/json' \
--data '
{
"customer_id": "0a9b8c7d-6e5f-4a3b-8c2d-1e0f9a8b7c6d",
"amount": "250.00",
"source": {
"source_type": "internal_account",
"id": "8e1a3c5b-7d9f-4b2e-a4c6-0e2f4a6c8b1d"
},
"destination": {
"destination_type": "external_account",
"id": "4f3e2d1c-0b9a-4876-9543-2a1b0c9d8e7f"
},
"client_reference": "adire-inv-3310",
"additional_information": {
"remitter_full_name": "Tunde Bakare",
"remitter_date_of_birth": "1984-07-22",
"remitter_country": "NG",
"remitter_address": {
"address_line1": "22 Creek Road",
"city": "Apapa",
"postal_code": "102272",
"state": "NG-LA",
"country": "NG"
}
}
}
'
const response = await fetch("https://api.gravv.xyz/v1/transfer", {
method: "POST",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
"Idempotency-Key": "47e3da9e-3600-41b1-90a2-9cc43beeb744",
"Content-Type": "application/json",
},
body: JSON.stringify({
"customer_id": "0a9b8c7d-6e5f-4a3b-8c2d-1e0f9a8b7c6d",
"amount": "250.00",
"source": {
"source_type": "internal_account",
"id": "8e1a3c5b-7d9f-4b2e-a4c6-0e2f4a6c8b1d"
},
"destination": {
"destination_type": "external_account",
"id": "4f3e2d1c-0b9a-4876-9543-2a1b0c9d8e7f"
},
"client_reference": "adire-inv-3310",
"additional_information": {
"remitter_full_name": "Tunde Bakare",
"remitter_date_of_birth": "1984-07-22",
"remitter_country": "NG",
"remitter_address": {
"address_line1": "22 Creek Road",
"city": "Apapa",
"postal_code": "102272",
"state": "NG-LA",
"country": "NG"
}
}
}),
});
console.log(response.status, await response.json());
import os
import requests
response = requests.post(
"https://api.gravv.xyz/v1/transfer",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
"Idempotency-Key": "47e3da9e-3600-41b1-90a2-9cc43beeb744",
"Content-Type": "application/json",
},
json={
"customer_id": "0a9b8c7d-6e5f-4a3b-8c2d-1e0f9a8b7c6d",
"amount": "250.00",
"source": {
"source_type": "internal_account",
"id": "8e1a3c5b-7d9f-4b2e-a4c6-0e2f4a6c8b1d",
},
"destination": {
"destination_type": "external_account",
"id": "4f3e2d1c-0b9a-4876-9543-2a1b0c9d8e7f",
},
"client_reference": "adire-inv-3310",
"additional_information": {
"remitter_full_name": "Tunde Bakare",
"remitter_date_of_birth": "1984-07-22",
"remitter_country": "NG",
"remitter_address": {
"address_line1": "22 Creek Road",
"city": "Apapa",
"postal_code": "102272",
"state": "NG-LA",
"country": "NG",
},
},
},
)
print(response.status_code, response.json())
Check that transfer_status is pending, not paused. Gravv uses the business's own email from its profile.
Fix a paused transfer
1. Recognize the pause
The transfer request returns 200, not an error:
{
"data": {
"amount": "250",
"amount_currency": "USD",
"reference": "c7d8e9f0-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
"transfer_status": "paused",
"transaction_id": "d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6",
"fee": "2",
"fee_currency": "USD",
"status": "awaiting_remitter_information",
"pause_reason": "sender_details_required",
"requirements": [
{"type": "remitter_full_name", "description": "resume with additional_information.remitter_full_name: the sender's first and last name"},
{"type": "remitter_date_of_birth", "description": "resume with additional_information.remitter_date_of_birth: the sender's date of birth as YYYY-MM-DD"}
],
"expires_at": "2026-10-16T11:20:05Z"
},
"error": null
}
The fee shown is an example. Your fee follows your pricing. Save reference.
2. Add the email if it is listed
If customer_email is in requirements, update the customer first. The email must be unique in your business.
curl --request PUT \
--url https://api.gravv.xyz/v1/customers/0a9b8c7d-6e5f-4a3b-8c2d-1e0f9a8b7c6d \
--header 'Api-Key: <API_KEY>' \
--header 'Content-Type: application/json' \
--data '
{
"email": "finance@adirelogistics.example"
}
'
const response = await fetch("https://api.gravv.xyz/v1/customers/0a9b8c7d-6e5f-4a3b-8c2d-1e0f9a8b7c6d", {
method: "PUT",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"email": "finance@adirelogistics.example"
}),
});
console.log(response.status, await response.json());
import os
import requests
response = requests.put(
"https://api.gravv.xyz/v1/customers/0a9b8c7d-6e5f-4a3b-8c2d-1e0f9a8b7c6d",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
"Content-Type": "application/json",
},
json={
"email": "finance@adirelogistics.example",
},
)
print(response.status_code, response.json())
3. Resume with every missing field in one call
curl --request POST \
--url https://api.gravv.xyz/v1/transfer/c7d8e9f0-a1b2-4c3d-8e4f-5a6b7c8d9e0f/resume \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: 0e6f40e4-59e1-445a-93aa-d829a53a7c24' \
--header 'Content-Type: application/json' \
--data '
{
"additional_information": {
"remitter_full_name": "Tunde Bakare",
"remitter_date_of_birth": "1984-07-22"
}
}
'
const response = await fetch("https://api.gravv.xyz/v1/transfer/c7d8e9f0-a1b2-4c3d-8e4f-5a6b7c8d9e0f/resume", {
method: "POST",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
"Idempotency-Key": "0e6f40e4-59e1-445a-93aa-d829a53a7c24",
"Content-Type": "application/json",
},
body: JSON.stringify({
"additional_information": {
"remitter_full_name": "Tunde Bakare",
"remitter_date_of_birth": "1984-07-22"
}
}),
});
console.log(response.status, await response.json());
import os
import requests
response = requests.post(
"https://api.gravv.xyz/v1/transfer/c7d8e9f0-a1b2-4c3d-8e4f-5a6b7c8d9e0f/resume",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
"Idempotency-Key": "0e6f40e4-59e1-445a-93aa-d829a53a7c24",
"Content-Type": "application/json",
},
json={
"additional_information": {
"remitter_full_name": "Tunde Bakare",
"remitter_date_of_birth": "1984-07-22",
},
},
)
print(response.status_code, response.json())
{
"data": {
"transfer_id": "c7d8e9f0-a1b2-4c3d-8e4f-5a6b7c8d9e0f",
"status": "approved_awaiting_execution",
"transfer_status": "pending",
"resumed": true
},
"error": null
}
Gravv merges the fields you send one by one into the original request, so send only what the response listed. The resume runs the transfer's checks again: balance, payee, rate, limits and sender details.
4. If the answer is resumed: false
The response lists what is still missing. Send those details in a new resume with another new key. The same key replays the old resumed: false.
5. Fix the profile for next time
For a person, add date_of_birth and address with PUT /v1/customers/{customer_id}, so later payouts do not pause. For a business, keep sending the director in additional_information.
What can go wrong
| Response | Why | Fix |
|---|---|---|
Every payout for a business pauses with remitter_full_name and remitter_date_of_birth |
A business profile has no person's name or date of birth | Send a director in additional_information on each payout |
remitter_full_name still listed after you sent "Tunde" |
With one word, the last name is empty | Send a first and last name |
remitter_address still listed after you sent only city |
An address you send replaces the profile address as a whole | Send address_line1, city and postal_code together |
remitter_country listed although you sent "Nigeria" |
The country must be an ISO code | Send "NG" |
400 remitter_date_of_birth must be a date as YYYY-MM-DD / remitter_date_of_birth cannot be in the future |
The format is wrong, or the year has a typo | Send a date such as "1984-07-22", with a new key |
400 invalid request body: json: unknown field "remitter_full_name" on resume |
You sent the field at the top level | Nest it inside additional_information |
410 this paused transfer has expired and can no longer be resumed; please initiate a new transfer |
The pause passed expires_at, and Gravv refunded the fee |
Start a new transfer, with additional_information |
410 this paused transfer was cancelled and can no longer be resumed; please initiate a new transfer |
Gravv cancelled it (reason sender_details_cancelled) |
Start a new transfer |
| Support cannot release it for you | The paying bank would refuse it without the details | Resume with the details |
Webhooks you will receive
transfer.requires_information, withevent_data.statuspaused,reasonsender_details_required, andlimit_details.requirements[], the same list as in the response.- After a successful resume,
transfer.resumed(reasonresumed), then the usualtransfer.status.pendingandtransfer.status.completed. - If the pause expires or Gravv cancels it,
transfer.status.failedwithreasonsender_details_expiredorsender_details_cancelled.
See Transfer events.
Testing in sandbox
Whether a sandbox payout reaches a route that needs sender details depends on the sandbox setup, so the pause may not appear. You can test that Gravv accepts a business payout with additional_information.