Create a card application
A card needs an approved application, and activating virtual_cards creates it. Follow the application in sandbox and in live.
You cannot create a card on its own. Every card needs an approved card application behind it, where Gravv's card program runs its own checks on the cardholder. You create the application by activating the card feature for the customer.
A money example. You activate cards for Ada with a daily limit of 300 USD in mind. In sandbox, the card program approves her application at once, and a virtual card with a 300 USD daily limit appears about 4 seconds later. In live, the card program reviews her application first. Once it is approved, you issue the card and fund it with 150 USD.
Before you start
- Your card account is
active. Itsidis theaccount_idbelow. - The customer's
basicKYC iscompleted, with a liveness check. See Card KYC and activation. - If you use a scoped API key, it needs
feature:readandfeature:activate.
Activate the card feature
Call Activate feature with feature_id virtual_cards:
curl --request POST \
--url https://api.gravv.xyz/v1/risk/features/activate \
--header 'Api-Key: <API_KEY>' \
--header 'Idempotency-Key: f0444862-29aa-44bc-821a-29e0e137497c' \
--header 'Content-Type: application/json' \
--data '
{
"customer_id": "5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42",
"feature_id": "virtual_cards",
"provider_data": {
"annual_remuneration": 24000,
"estimated_monthly_limit": 300,
"account_id": "9b40be8d-9d74-4d2a-8897-dea3ef80ad23"
}
}
'
| Field | Rule |
|---|---|
annual_remuneration |
Yearly income in USD, a JSON number of at least 1000 |
estimated_monthly_limit |
A JSON number of at least 1. When a card is issued during activation (sandbox), it becomes that card's daily limit |
account_id |
Always your card account's id, for every cardholder |
Gravv fills in ip_address from the address your request comes from.
{
"data": {
"activated_at": "2026-10-13T11:20:05Z",
"customer_id": "5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42",
"feature_id": "virtual_cards",
"status": "active"
},
"error": null
}
status active means Gravv submitted the application. It does not mean a card exists, and the response carries no application id. If the customer has no liveness check yet, the response has status pending_liveness and a websdk_url. See Activate feature.
Find the application
curl --request GET \
--url 'https://api.gravv.xyz/v1/cards?customer_id=5b0f6c1e-2a8f-4c39-9d0e-0c7e3b9a1f42' \
--header 'Api-Key: <API_KEY>'
- Sandbox. The card program approves the application at once, and Gravv issues a virtual card during activation. The list shows it with
statusactive. Do not call Create a card unless you want a second card. - Live. The list shows an application row with
status""(no card yet). Itsidis the application id, and it will also be the first card's id.
Live: follow the approval
Only List card applications shows application_status. The list has no customer filter, so page through it and match customer_id. Get card application returns the card status. That status stays "" until a card exists, so never poll it for approval.
curl --request GET \
--url 'https://api.gravv.xyz/v1/cards/applications?items_per_page=100' \
--header 'Api-Key: <API_KEY>'
application_status |
What to do |
|---|---|
pending, manual_review |
Wait for cards.application.update |
needs_verification, needs_information |
Show the cardholder the application_link, then wait for cards.application.update |
approved |
Create the card |
denied, locked, canceled |
Stop and contact support |
In sandbox, application_link is always "".
What can go wrong
| Response | Why | Fix |
|---|---|---|
400 cards service: internal server error |
account_id left out, a number sent as a string, or the card program refused |
Send account_id, and send numbers as numbers. If the error persists, contact support with the customer id |
400 failed to check liveness requirement: customer KYC must be completed before activating cards feature |
KYC not finished | Wait for customer.kyc.status.completed |
200 with message Feature activation already exists with status: active |
Already activated | Find the card with GET /v1/cards?customer_id=… |
400 card application is not yet approved! on POST /v1/cards |
Live application still under review | Wait for approved, then send a new Idempotency-Key |
Gravv stores every failed request against its Idempotency-Key for 24 hours. After you fix a request, send it with a new key.
The application route
Create card application (POST /v1/cards/applications/new) works today only for business cards in sandbox. Live does not support it. Use activation for every individual cardholder.