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.

Was this page helpful?