Pay a UK account by Faster Payments
Save a UK sort code and account number as a Faster Payments payee and send a GBP payout from a wallet-backed account.
Use this recipe to save a UK sort code and account number as a Faster Payments payee and send a GBP payout from a wallet-backed account.
Who it is for. A US marketplace that pays a UK seller's sterling account.
Status. Available from wallet-backed accounts to GB, if Gravv has enabled Faster Payments for your business. Not supported from bank-held USD accounts. Gravv does not support CHAPS or BACS.
Money example
- The marketplace's wallet-backed USD account holds 3,000.00 USD.
- The marketplace sends 800.00 USD to Oliver Bennett's UK account.
- At an example rate of 0.75 GBP per USD, the response shows 600.00 GBP for Oliver in
local_amount. Gravv debits the account 800.00 USD plus the fee on your plan.
Before you start
You need the same as for SEPA:
- A wallet-backed source account.
- Faster Payments enabled for your business.
- The seller's sort code, account number, name and address.
Find out what is required
- Payee rules. Set
payee_typetofpsandcurrencytoGBP, the only currency allowed. Put the 6-digit sort code inrouting_number. Sendaccount_numberas 4 to 34 letters or digits with no spaces. Also sendaccount_owner_type,bank_nameandaddress. - Always send
payee_typefps. Without it, Gravv guesses the payee type from the details, and a mistyped routing number can turn the payee into a US payee. - Indicative rate. Call
GET /v1/transfer/rates?currency=GBPand read the item withdirectionUSD_GBP.
Steps
1. Save the Faster Payments payee
curl --request POST \
--url https://api.gravv.xyz/v1/external-accounts \
--header 'Api-Key: <API_KEY>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 70145bba-a8e7-4f2f-8700-4160600e6cbe' \
--data '
{
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"payee_type": "fps",
"currency": "GBP",
"account_name": "Oliver Bennett",
"routing_number": "601613",
"account_number": "31926819",
"account_owner_type": "individual",
"bank_name": "NatWest",
"address": {
"address_line1": "221 Baker Street",
"city": "London",
"postal_code": "NW1 6XE",
"country": "GB"
}
}
'
const response = await fetch("https://api.gravv.xyz/v1/external-accounts", {
method: "POST",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
"Content-Type": "application/json",
"Idempotency-Key": "70145bba-a8e7-4f2f-8700-4160600e6cbe",
},
body: JSON.stringify({
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"payee_type": "fps",
"currency": "GBP",
"account_name": "Oliver Bennett",
"routing_number": "601613",
"account_number": "31926819",
"account_owner_type": "individual",
"bank_name": "NatWest",
"address": {
"address_line1": "221 Baker Street",
"city": "London",
"postal_code": "NW1 6XE",
"country": "GB"
}
}),
});
console.log(response.status, await response.json());
import os
import requests
response = requests.post(
"https://api.gravv.xyz/v1/external-accounts",
headers={
"Api-Key": os.environ["GRAVV_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": "70145bba-a8e7-4f2f-8700-4160600e6cbe",
},
json={
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"payee_type": "fps",
"currency": "GBP",
"account_name": "Oliver Bennett",
"routing_number": "601613",
"account_number": "31926819",
"account_owner_type": "individual",
"bank_name": "NatWest",
"address": {
"address_line1": "221 Baker Street",
"city": "London",
"postal_code": "NW1 6XE",
"country": "GB",
},
},
)
print(response.status_code, response.json())
{
"data": {
"account_name": "OLIVER BENNETT",
"account_number": "31926819",
"account_owner_type": "individual",
"address": {
"address_line1": "221 Baker Street",
"city": "London",
"country": "GB",
"postal_code": "NW1 6XE"
},
"currency": "GBP",
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"date_created": "2026-10-13T22:41:25.016918Z",
"id": "7b1a2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
"institution_name": "NatWest",
"payee_type": "fps",
"routing_number": "601613",
"status": "pending"
},
"error": null
}
The payee starts as pending. Wait for the external_account.active webhook before you send the payout.
2. Send the payout
curl --request POST \
--url https://api.gravv.xyz/v1/transfer \
--header 'Api-Key: <API_KEY>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: c72fcd5c-b78d-4442-b1b3-c89df886eef9' \
--data '
{
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"source": {
"source_type": "internal_account",
"id": "9b2d6f0e-3c1a-4e8b-a7d5-2f4c6e8a0b13"
},
"destination": {
"destination_type": "external_account",
"id": "7b1a2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
"rail": "fps"
},
"amount": "800.00",
"description": "Marketplace payout order 5590",
"client_reference": "fps-ob-5590"
}
'
const response = await fetch("https://api.gravv.xyz/v1/transfer", {
method: "POST",
headers: {
"Api-Key": process.env.GRAVV_API_KEY,
"Content-Type": "application/json",
"Idempotency-Key": "c72fcd5c-b78d-4442-b1b3-c89df886eef9",
},
body: JSON.stringify({
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"source": {
"source_type": "internal_account",
"id": "9b2d6f0e-3c1a-4e8b-a7d5-2f4c6e8a0b13"
},
"destination": {
"destination_type": "external_account",
"id": "7b1a2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
"rail": "fps"
},
"amount": "800.00",
"description": "Marketplace payout order 5590",
"client_reference": "fps-ob-5590"
}),
});
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"],
"Content-Type": "application/json",
"Idempotency-Key": "c72fcd5c-b78d-4442-b1b3-c89df886eef9",
},
json={
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"source": {
"source_type": "internal_account",
"id": "9b2d6f0e-3c1a-4e8b-a7d5-2f4c6e8a0b13",
},
"destination": {
"destination_type": "external_account",
"id": "7b1a2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
"rail": "fps",
},
"amount": "800.00",
"description": "Marketplace payout order 5590",
"client_reference": "fps-ob-5590",
},
)
print(response.status_code, response.json())
{
"data": {
"amount": "800",
"amount_currency": "USD",
"reference": "8e0a2c4e-6f8b-4a0c-b2e4-6a8c0e2f4b56",
"date_created": "2026-10-13T11:20:00.000Z",
"transfer_status": "pending",
"transaction_id": "1c3e5a7c-9e1b-4c3e-a5c7-9e1b3d5f7a67",
"local_amount": "600",
"local_currency": "GBP",
"fee": "2",
"fee_currency": "USD",
"requires_approval": false
},
"error": null
}
3. Follow it to the end
The transaction shows transaction_type global_remittance and channel bank_transfer. The webhooks carry workflow_type fps_transfer.
What can go wrong
| Response | Why | Fix |
|---|---|---|
400 routing number (sort code) required but missing for fps payee: invalid input |
The request has no sort code | Send it in routing_number |
400 account number must not contain spaces |
The account number has spaces | Send 31926819, not 3192 6819 |
400 EUR not supported for fps external accounts: invalid input |
Faster Payments payees are GBP only | Send "currency": "GBP" |
| A GBP payee saved with a 9-digit routing number becomes a US payee and fails the USD rule | The request had no payee_type |
Always send "payee_type": "fps" |
400 a recipient with the same account name, account number and bank already exists, with data.payee_id |
A payee with the same customer, name, account number and sort code already exists. 60-16-13 and 601613 count as the same sort code |
Use data.payee_id |
400 account_number (UK sort code + account number) is required for FPS transfers |
The payee has no account number | Fix the payee or save a new one |
| Source, country and rate errors | The same errors as for SEPA, with GB/GBP |
See SEPA |
Webhooks you will receive
You receive the same webhooks as for SEPA.
Testing in sandbox
Sandbox simulates Faster Payments payee setup, and the payee becomes active in a few seconds. Everything else works as for SEPA.