Fund cards

Top up a card with a transfer from an internal account or a USDC wallet on the card's own network, then confirm it by reading the transaction.

This page shows how to put money on a card. You fund a card with a transfer whose destination is the card. There is no separate funding endpoint.

A money example. Ada's USD account holds 400 USD and her card holds 0. You send 150 USD from the account to the card. The account drops to 250 USD (less any transfer fee on your plan) and the card's balance reads 150 once the transfer is completed.

Rules

Rule Check
The card is not frozen or blocked Get card returns status active (or inactive)
The source is an internal account with a wallet, or an internal wallet holding USDC The account has wallet_address and blockchain_network. The wallet lists USDC in assets
The source is on the card's network The card's blockchain_network (for example polygon) equals the account's blockchain_network or the wallet's network
The source holds enough for the amount and the fee The account balance, or the wallet's USDC balance
amount is a string in US dollars, at most 2 decimals "150", "12.50"

An account that holds its money at a bank, with no wallet behind it, cannot fund a card.

From an account

curl --request POST \
     --url https://api.gravv.xyz/v1/transfer \
     --header 'Api-Key: <API_KEY>' \
     --header 'Idempotency-Key: 8a4545b4-294e-4621-9035-0c714c04e087' \
     --header 'Content-Type: application/json' \
     --data '
{
  "source": {
    "source_type": "internal_account",
    "id": "6f1c2b8e-9a43-4f0e-8d35-2b7f0f6c1a90"
  },
  "destination": {
    "destination_type": "card",
    "id": "a14ec356-f33d-4384-ba68-4d9bfa19765b"
  },
  "amount": "150",
  "customer_id": "5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42",
  "client_reference": "ada-card-topup-0001",
  "description": "Card top-up"
}
'

customer_id is the owner of the source. When a company funds an employee's card from its own account, send the company's id. The card still belongs to the employee.

From a wallet

curl --request POST \
     --url https://api.gravv.xyz/v1/transfer \
     --header 'Api-Key: <API_KEY>' \
     --header 'Idempotency-Key: 2265fc7c-ea99-4d81-85fa-7d2b029cb7d9' \
     --header 'Content-Type: application/json' \
     --data '
{
  "source": {
    "source_type": "internal_crypto_wallet",
    "id": "67e169c0-547f-410d-8e18-f616b6822d70",
    "crypto_asset": "USDC"
  },
  "destination": {
    "destination_type": "card",
    "id": "e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e"
  },
  "amount": "100",
  "customer_id": "0d6c2f4e-6a1b-4f0e-9b8f-5c2a7d3e1f00",
  "client_reference": "tunde-topup-0001"
}
'

Confirm it

The answer contains transaction_id and a transfer_status of pending. A paused status means a limit on your platform held the transfer. See Transfer limits.

  1. Poll Get transaction until status is completed or failed. The transaction's transaction_type is card_funding.
  2. Read the card's balance.

Do not wait for a funding webhook. You may receive transfer.status.completed (with workflow_type card_funding) and cards.transaction.funding, but Gravv does not guarantee them.

What can go wrong

Response Why Fix
400 this card is freeze and cannot be funded / this card is blocked and cannot be funded The card is frozen or blocked Unfreeze the card first. You cannot use a blocked card again
400 the source account (ethereum network) and destination (polygon network) must be on the same blockchain network The source is on another network Use a source on the card's network
400 this account can only send to a bank account or to another account held at the same bank The source account holds its money at a bank Use an account with a wallet, or a USDC wallet
400 the destination card has no wallet provisioned yet The card is not issued yet Issue the card first
400 no card account found for id <card> (customer <id>) The card id is wrong, or the card is not yours Check it with GET /v1/cards?card_id=…
400 insufficient balance The amount and fee are more than the source balance Lower the amount or fund the source
400 source_type must be one of: internal_account, internal_crypto_wallet, card You sent crypto_wallet Use internal_crypto_wallet
400 the source account could not be verified for this transfer — please try again shortly A temporary check failed Retry once with a new key. If it fails again, contact support
Gravv accepts the transfer, then it becomes failed amount had more than 2 decimals Send at most 2 decimals

After any 400, fix the request and send it with a new Idempotency-Key. Gravv replays a failed answer for 24 hours under the old key.

Was this page helpful?