---
title: "Fix a payee that failed setup"
description: "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](/getting-started/glossary).

**Who it is for.** Any business whose SEPA, Faster Payments, SWIFT or US payee came back `setup_failed`.

**Status.** Available.

## Money example

1. A SWIFT payee for a 7,500.00 USD supplier payment fails setup with `error_message` `these account details could not be accepted`.
2. The supplier confirms that the account number ends in 8, not 9.
3. You correct the payee. It goes back to `pending`, then `active`, 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`:

<CodeGroup>
```bash title="cURL"
curl --request GET \
     --url https://api.gravv.xyz/v1/external-accounts/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
     --header 'Api-Key: <API_KEY>'
```
```javascript title="Node"
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());
```
```python title="Python"
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())
```
</CodeGroup>

```json title="Response"
{
  "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`.

<CodeGroup>
```bash title="cURL"
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"
}
'
```
```javascript title="Node"
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());
```
```python title="Python"
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())
```
</CodeGroup>

```json title="Response (HTTP 202)"
{
  "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)`.

## Reference

- [Update an external account](/platform/external-accounts/update-an-external-account)
- [`PATCH /v1/external-accounts/{external_account_id}`](/api-reference/external-accounts/patch-v1-external-accounts-external-account-id)
