Fix a payee that failed setup
Read why a payee came back setup_failed, correct it in place with PATCH, and pay it without saving a duplicate.
Read why a payee came back setup_failed, correct it in place with PATCH, and pay it without saving a duplicate. A payee is an external account, a bank account outside Gravv that a customer pays. See the Glossary.
Who it is for. Any business whose SEPA, Faster Payments, SWIFT or US payee came back setup_failed.
Status. Available.
Money example
- A SWIFT payee for a 7,500.00 USD supplier payment fails setup with
error_messagethese account details could not be accepted. - The supplier confirms that the account number ends in 8, not 9.
- You correct the payee. It goes back to
pending, thenactive, and you send the 7,500.00 USD.
Before you start
You need the payee id. You cannot save the same payee again. A failed payee still counts as a duplicate, so a new create request returns the failed payee's id.
Find out what is required
Read the payee and its error_message:
curl --request GET \
--url https://api.gravv.xyz/v1/external-accounts/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
--header 'Api-Key: <API_KEY>'
const response = await fetch("https://api.gravv.xyz/v1/external-accounts/f47ac10b-58cc-4372-a567-0e02b2c3d479", {
method: "GET",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
},
});
console.log(response.status, await response.json());
import os
import requests
response = requests.get(
"https://api.gravv.xyz/v1/external-accounts/f47ac10b-58cc-4372-a567-0e02b2c3d479",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
},
)
print(response.status_code, response.json())
{
"data": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"payee_type": "swift",
"account_number": "1012345679",
"account_name": "ADEBAYO TEXTILES LTD",
"bic": "ZEIBNGLA",
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"currency": "USD",
"account_owner_type": "business",
"status": "setup_failed",
"date_created": "2026-10-13T10:00:00.000Z",
"error_message": "these account details could not be accepted"
},
"error": null
}
error_message |
What to do |
|---|---|
these account details could not be accepted (sometimes … for the <rail> rail) |
A detail is wrong. Check each field with the payee |
account setup did not complete (attempt N of 10) |
Setup kept failing to complete. Check the fields, or retry with no changes |
recipient setup failed |
Check the fields, or retry with no changes |
Steps
1. Correct the payee
Send only the fields that change. Gravv keeps a field you leave out, clears a field you send as null, and sets a field you send with a value. Never send "" to clear a field. PATCH needs no Idempotency-Key.
curl --request PATCH \
--url https://api.gravv.xyz/v1/external-accounts/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
--header 'Api-Key: <API_KEY>' \
--header 'Content-Type: application/json' \
--data '
{
"account_number": "1012345678"
}
'
const response = await fetch("https://api.gravv.xyz/v1/external-accounts/f47ac10b-58cc-4372-a567-0e02b2c3d479", {
method: "PATCH",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
"account_number": "1012345678"
}),
});
console.log(response.status, await response.json());
import os
import requests
response = requests.patch(
"https://api.gravv.xyz/v1/external-accounts/f47ac10b-58cc-4372-a567-0e02b2c3d479",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
"Content-Type": "application/json",
},
json={
"account_number": "1012345678",
},
)
print(response.status_code, response.json())
{
"data": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"payee_type": "swift",
"account_number": "1012345678",
"account_name": "ADEBAYO TEXTILES LTD",
"bic": "ZEIBNGLA",
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"currency": "USD",
"account_owner_type": "business",
"status": "pending",
"date_created": "2026-10-13T10:00:00.000Z"
},
"error": null
}
To retry setup with no changes, for example after attempt 10 of 10, send {}.
2. Wait for the new setup
The PATCH itself sends no event. Wait for external_account.active, or for external_account.setup_failed again. Then pay the payee as its recipe describes.
What can go wrong
| Response | Why | Fix |
|---|---|---|
409 payee <id> is not correctable in its current state (active): invalid state transition |
You can change banking details only on a setup_failed payee, or on a pending payee whose setup has not started |
Save a new payee |
409 the same message with (pending) |
Setup has already started | Wait for active or setup_failed |
| 409, duplicate | The corrected details match another payee | Use that payee |
409 the address of payee <id> cannot be changed: it is already registered for payouts; create a new payee with the new address |
Gravv locked the address when it registered the payee for payouts | Save a new payee |
409 payee <id> was changed by another request while this update was applied; reload it and retry: invalid input |
Two updates ran at the same time | Read the payee, then PATCH again |
400 account name cannot be cleared: invalid input |
You sent "account_name": null |
Send a value |
404 payee <id>: resource not found |
The id is unknown | Check the id |
currency, payee_type, phone_number, customer_id or internal_account_id did not change |
You cannot change these fields, and Gravv ignores them | Save a new payee |
500 We couldn't update this payee. Please try again later. |
The server had an error | Retry |
Webhooks you will receive
Gravv sends no event for the PATCH. After it, Gravv sends external_account.active or external_account.setup_failed.
Testing in sandbox
The PATCH checks and state rules work as in live. Sandbox simulates payee setup, which finishes in a few seconds. So you cannot produce a setup_failed payee in sandbox, and a PATCH sent one second after saving already returns 409 (pending).