Issue and manage cards
This recipe takes an individual customer from creation through card issuance, funding, and withdrawal.
Before you start, identify the funded internal account that will back and fund the card. Every POST request in this recipe requires an Idempotency-Key. Use a new value for each operation, and reuse that value only when retrying the same operation with the same payload.
Flow overview
sequenceDiagram
autonumber
actor Client
participant API as Gravv API
actor Customer
Client->>API: Create customer and start verification
API-->>Customer: Verification session
Customer->>API: Complete verification
Client->>API: Create backing account and activate cards
alt Liveness or manual review required
API-->>Client: pending_liveness or manual_review
Client->>API: Poll application status
else Application approved
API-->>Client: approved
end
Client->>API: Issue card
loop Until card is ready
Client->>API: Retrieve card
API-->>Client: Current card status
end
Client->>API: Fund or withdraw from card
API-->>Client: Processing result
Create the individual customer who will own the card.
curl --request POST \
--url https://api.gravv.xyz/v1/customers \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: customer-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"first_name": "Sarah",
"last_name": "Johnson",
"email": "sarah.johnson@example.com",
"phone": "+14155552345",
"type": "individual",
"gender": "female",
"date_of_birth": "1990-03-15",
"address": {
"address_line1": "123 Market Street",
"city": "San Francisco",
"postal_code": "94102",
"state": "US-CA",
"country": "US"
}
}'
{
"data": {
"id": "9e3cccad-e9ae-47a0-81ee-063af0159310",
"first_name": "Sarah",
"last_name": "Johnson",
"type": "individual",
"status": "active"
},
"error": null
}
Save data.id as the customer ID.
Start KYC for the customer, then direct them to the returned verification URL. Wait for KYC to reach completed before continuing.
curl --request POST \
--url https://api.gravv.xyz/v1/customers/kyc/start \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: kyc-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"customer_id": "9e3cccad-e9ae-47a0-81ee-063af0159310"
}'
{
"data": {
"status": "success",
"web_url": "https://verify.gravv.xyz/websdk/p/example_token"
},
"error": null
}
Use KYC status or customer KYC webhooks to confirm completion.
Create the USD account that will back the customer's card.
curl --request POST \
--url https://api.gravv.xyz/v1/accounts \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: card-account-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"currency": "USD",
"type": "regular",
"blockchain_network": "polygon",
"label": "Sarah Johnson card account",
"customer_id": "9e3cccad-e9ae-47a0-81ee-063af0159310"
}'
{
"data": {
"id": "5d9e677f-f071-4881-a861-7cdcebacd9d5",
"customer_id": "9e3cccad-e9ae-47a0-81ee-063af0159310",
"currency": "USD",
"type": "regular",
"status": "active"
},
"error": null
}
Save data.id as the backing account ID.
Activate virtual_cards. This creates the card application used for issuance.
curl --request POST \
--url https://api.gravv.xyz/v1/risk/features/activate \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: card-activation-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"customer_id": "9e3cccad-e9ae-47a0-81ee-063af0159310",
"feature_id": "virtual_cards",
"provider_data": {
"annual_remuneration": 75000,
"estimated_monthly_limit": 2000,
"ip_address": "192.0.2.10",
"account_id": "5d9e677f-f071-4881-a861-7cdcebacd9d5"
}
}'
{
"data": {
"customer_id": "9e3cccad-e9ae-47a0-81ee-063af0159310",
"feature_id": "virtual_cards",
"status": "active",
"activated_at": "2026-01-09T10:29:16.000Z",
"data": {
"application_id": "a14ec356-f33d-4384-ba68-4d9bfa19765b"
}
},
"error": null
}
Save data.data.application_id. If activation returns pending_liveness, send the customer to websdk_url, complete the check, and retry with the same idempotency key.
Retrieve the application until application_status becomes approved. Stop if it becomes denied, locked, or canceled.
curl --request GET \
--url https://api.gravv.xyz/v1/cards/applications/a14ec356-f33d-4384-ba68-4d9bfa19765b \
--header 'Api-Key: <API_KEY>'
{
"data": {
"id": "a14ec356-f33d-4384-ba68-4d9bfa19765b",
"customer_id": "9e3cccad-e9ae-47a0-81ee-063af0159310",
"application_status": "approved"
},
"error": null
}
Create the card after the application is approved.
curl --request POST \
--url https://api.gravv.xyz/v1/cards \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: card-issuance-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"customer_id": "9e3cccad-e9ae-47a0-81ee-063af0159310",
"card_type": "virtual",
"card_limit": 500,
"name_on_card": "Sarah Johnson"
}'
{
"data": {
"id": "dce0192a-9b3d-440b-9500-33dc9ac8dc20",
"message": "Card creation request is processing",
"status": true,
"fee_charged": true,
"fee_pending": false
},
"error": null
}
Save data.id as the card ID. Retrieve the card until its status is ready for use.
Transfer funds from a funded internal account to the issued card.
curl --request POST \
--url https://api.gravv.xyz/v1/transfer \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: card-funding-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"source": {
"source_type": "internal_account",
"id": "b9c2cb0d-e09a-496f-8655-d8c4b7aaf2f8"
},
"destination": {
"destination_type": "card",
"id": "dce0192a-9b3d-440b-9500-33dc9ac8dc20"
},
"amount": 250,
"description": "Initial card funding",
"customer_id": "9e3cccad-e9ae-47a0-81ee-063af0159310",
"client_reference": "card-fund-2026-001"
}'
{
"data": {
"amount": "250",
"reference": "550e8400-e29b-41d4-a716-446655440000",
"transfer_status": "pending",
"transaction_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
},
"error": null
}
Track the transfer until it completes before allowing the customer to spend the funds.
Move unused card funds back to the account configured during card activation.
curl --request POST \
--url https://api.gravv.xyz/v1/cards/withdraw \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: card-withdrawal-<UUID>' \
--header 'Content-Type: application/json' \
--data '{
"card_id": "dce0192a-9b3d-440b-9500-33dc9ac8dc20",
"amount": 100
}'
{
"data": {
"tx_hash": "0x2e5d0af9189b4b4c23bc64b96295e730609ec91e50e452a5da0a4af4bfe5c192"
},
"error": null
}
See Cards, card applications, and the Cards API Reference for lifecycle and status details.