Remit funds to a recipient
This recipe creates an external recipient, waits until the recipient is active, and transfers funds from a funded Gravv account.
Before you start, you need the sender's funded internal account ID and the recipient's Gravv customer ID. Both POST requests in this recipe require an Idempotency-Key. Use a new key for each operation and reuse it only when retrying the same operation with the same payload.
Flow overview
sequenceDiagram
autonumber
actor Client
participant API as Gravv API
participant Rail as Payment rail
Client->>API: Create external recipient
API->>Rail: Set up recipient
alt Recipient is immediately active
API-->>Client: active
else Setup is asynchronous
API-->>Client: pending
loop Until terminal status
Client->>API: Retrieve external recipient
API-->>Client: pending, active, or failed
end
end
Client->>API: Transfer to active recipient
API->>Rail: Submit payout
API-->>Client: pending or completed
opt Transfer is asynchronous
Client->>API: Retrieve transfer status
API-->>Client: completed or failed
end
Create an external account for the recipient. This example adds a US bank account; use the recipient type and fields required for your transfer corridor.
curl --request POST \
--url https://api.gravv.xyz/v1/external-accounts \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: recipient-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"payee_type": "ach_wire",
"account_number": "000123456789",
"account_name": "Amina Bello",
"bank_name": "Example Community Bank",
"currency": "USD",
"customer_id": "373556ec-74e5-4cde-909c-b94d864915db",
"routing_number": "000000000",
"account_owner_type": "individual",
"account_type": "savings",
"address": {
"address_line1": "1800 N Pole St",
"city": "Orlando",
"state": "US-FL",
"postal_code": "32801",
"country": "US"
}
}'
{
"data": {
"id": "e0c0d076-fd86-4739-b26d-527ab83ab033",
"customer_id": "373556ec-74e5-4cde-909c-b94d864915db",
"account_name": "Amina Bello",
"currency": "USD",
"payee_type": "ach_wire",
"status": "pending"
},
"error": null
}
Save data.id as the external account ID. A 200 response can return status: active; a 202 response returns status: pending while setup continues.
If setup is pending, retrieve the external account until its status becomes active. You can also subscribe to payee.setup.* webhook events.
curl --request GET \
--url https://api.gravv.xyz/v1/external-accounts/e0c0d076-fd86-4739-b26d-527ab83ab033 \
--header 'Api-Key: <API_KEY>'
{
"data": {
"id": "e0c0d076-fd86-4739-b26d-527ab83ab033",
"status": "active"
},
"error": null
}
Use the active external account ID as the transfer destination.
curl --request POST \
--url https://api.gravv.xyz/v1/transfer \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: remittance-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"source": {
"source_type": "internal_account",
"id": "b9c2cb0d-e09a-496f-8655-d8c4b7aaf2f8"
},
"destination": {
"destination_type": "external_account",
"id": "e0c0d076-fd86-4739-b26d-527ab83ab033",
"rail": "wire"
},
"amount": 150,
"client_reference": "remittance-2026-001",
"description": "Supplier payment",
"customer_id": "bb6c6022-f1d8-492f-80f0-7547134bb42f"
}'
{
"data": {
"amount": "150",
"reference": "550e8400-e29b-41d4-a716-446655440000",
"date_created": "2026-07-10T10:30:00Z",
"transfer_status": "pending",
"transaction_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"local_amount": null,
"local_currency": null
},
"error": null
}
Store the transfer reference and transaction ID for reconciliation. Track the final status through transfer webhooks or transaction retrieval.
See External Accounts for other recipient types and Transfers for corridor-specific requirements.