---
title: "Close a card and get the money back"
description: "Taking money off a new card is Not yet available. See what each route returns today, and the order to follow once it is available."
---
Use this recipe to take the money off a card before you block it. For new cards, this is Not yet available. The page shows what each route returns today and the order to follow once it is available.

**Who it is for.** A consumer app whose user closes their account, or an expense platform whose employee leaves.

**Status.** Not yet available for new cards. Today both routes refuse new cards. Contact support to move money off a card.

## Money example

Tunde's card holds 435.80 USD.

1. You withdraw 435.80 USD from the card to the card account. The card now holds 0 USD.
2. You block the card.
3. You send the 435.80 USD onward with a normal transfer.

Today the API refuses step 1 on new cards, so his employer freezes the card and asks support to move the 435.80 USD.

## Before you start

| Prerequisite | How to check |
| :-- | :-- |
| The card is `active`. You cannot withdraw from a frozen or blocked card | `GET /v1/cards/{card_id}` |
| The amount on the card | `GET /v1/cards/{card_id}/balance` |

**Withdraw before you block.** If `shared` is `true`, the balance belongs to several cards, and withdrawing takes money the other cards can spend.

## Find out what is required

The withdraw call tells you which route a card uses. For a card that withdraws by transfer, the call returns `this card withdraws by transfer: send a transfer from the card to its account`.

## Steps

### 1. Read the balance

<CodeGroup>
```bash title="cURL"
curl --request GET \
     --url https://api.gravv.xyz/v1/cards/e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e/balance \
     --header 'Api-Key: <API_KEY>'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/cards/e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e/balance", {
  method: "GET",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
  },
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.get(
    "https://api.gravv.xyz/v1/cards/e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e/balance",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

### 2. Try to withdraw

<CodeGroup>
```bash title="cURL"
curl --request POST \
     --url https://api.gravv.xyz/v1/cards/withdraw \
     --header 'Api-Key: <API_KEY>' \
     --header 'Idempotency-Key: 7f2155fe-7a1e-4302-83d0-09464cf8bce9' \
     --header 'Content-Type: application/json' \
     --data '
{
  "card_id": "e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
  "amount": 435.8
}
'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/cards/withdraw", {
  method: "POST",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
    "Idempotency-Key": "7f2155fe-7a1e-4302-83d0-09464cf8bce9",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "card_id": "e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
    "amount": 435.8
  }),
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.post(
    "https://api.gravv.xyz/v1/cards/withdraw",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
        "Idempotency-Key": "7f2155fe-7a1e-4302-83d0-09464cf8bce9",
        "Content-Type": "application/json",
    },
    json={
        "card_id": "e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
        "amount": 435.8,
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

`amount` is a JSON number in dollars with at most 2 decimals. The money can go only to the card's own card account. For a card that supports this route, the call returns `{"data":{"tx_hash":"0x…"},"error":null}`, and you then receive `cards.transaction.withdraw`. For new cards, the call returns `this card withdraws by transfer: send a transfer from the card to its account`.

### 3. The transfer route

Gravv designed new cards to withdraw with a transfer from the card to its own card account, with the cardholder as `customer_id`. Read the card account's `account_id` from `GET /v1/cards?card_id=…`. Today the API refuses this route too:

<CodeGroup>
```bash title="cURL"
curl --request POST \
     --url https://api.gravv.xyz/v1/transfer \
     --header 'Api-Key: <API_KEY>' \
     --header 'Idempotency-Key: 0107108a-0aed-439b-9e28-41368831ad2e' \
     --header 'Content-Type: application/json' \
     --data '
{
  "source": {
    "source_type": "card",
    "id": "e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e"
  },
  "destination": {
    "destination_type": "internal_account",
    "id": "9b40be8d-9d74-4d2a-8897-dea3ef80ad23"
  },
  "amount": "435.80",
  "customer_id": "c3a1f2e4-7b6d-4e8a-9c0b-1d2e3f4a5b6c",
  "client_reference": "tunde-card-out-0001"
}
'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/transfer", {
  method: "POST",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
    "Idempotency-Key": "0107108a-0aed-439b-9e28-41368831ad2e",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "source": {
      "source_type": "card",
      "id": "e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e"
    },
    "destination": {
      "destination_type": "internal_account",
      "id": "9b40be8d-9d74-4d2a-8897-dea3ef80ad23"
    },
    "amount": "435.80",
    "customer_id": "c3a1f2e4-7b6d-4e8a-9c0b-1d2e3f4a5b6c",
    "client_reference": "tunde-card-out-0001"
  }),
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.post(
    "https://api.gravv.xyz/v1/transfer",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
        "Idempotency-Key": "0107108a-0aed-439b-9e28-41368831ad2e",
        "Content-Type": "application/json",
    },
    json={
        "source": {
            "source_type": "card",
            "id": "e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
        },
        "destination": {
            "destination_type": "internal_account",
            "id": "9b40be8d-9d74-4d2a-8897-dea3ef80ad23",
        },
        "amount": "435.80",
        "customer_id": "c3a1f2e4-7b6d-4e8a-9c0b-1d2e3f4a5b6c",
        "client_reference": "tunde-card-out-0001",
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

The call returns 400 `the balance for this account could not be confirmed — please try again shortly`. Do not retry it in a loop. Contact support instead.

### 4. Block the card

Block the card after the money is off it, or after support has moved the money:

<CodeGroup>
```bash title="cURL"
curl --request PATCH \
     --url https://api.gravv.xyz/v1/cards/e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e/update \
     --header 'Api-Key: <API_KEY>' \
     --header 'Content-Type: application/json' \
     --data '
{
  "status": "blocked",
  "limit": 200
}
'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/cards/e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e/update", {
  method: "PATCH",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "status": "blocked",
    "limit": 200
  }),
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.patch(
    "https://api.gravv.xyz/v1/cards/e7b1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e/update",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
        "Content-Type": "application/json",
    },
    json={
        "status": "blocked",
        "limit": 200,
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

## What can go wrong

| Response (HTTP 400) | Why | Fix |
| :-- | :-- | :-- |
| `this card withdraws by transfer: send a transfer from the card to its account` | The card is a new card | Not yet available. Contact support |
| `the balance for this account could not be confirmed — please try again shortly` | You used the transfer route on a new card | Not yet available. Contact support |
| `cannot withdraw from a freezed or blocked card` | The card is frozen, blocked or inactive | Unfreeze first. If blocked, contact support |
| `the source card does not belong to this customer` | `customer_id` is not the cardholder | Send the cardholder's id |
| `a card can only be withdrawn to its own card account (destination_type internal_account)` | The destination is not the card's own card account | Send the card's own `account_id` |
| `insufficient balance` | The amount is above the card balance | Read the balance again |
| `amount must be greater than zero` | The amount is 0 or negative | Send a positive amount |
| `a withdrawal for this idempotency key is already in progress; retry shortly` | You reused the key while the first call was still running | Wait, then retry |
| `internal server error` or `the request could not be completed` | The call failed, or you sent `amount` as a string | Read the balance and your webhooks **before** you retry. Then retry with a new key |

## Webhooks you will receive

When a withdrawal succeeds, you receive `cards.transaction.withdraw` with `transaction.status` and `transaction.amount`. When you block the card, you receive `cards.status.update` with `blocked`.

## Testing in sandbox

Both routes refuse new sandbox cards today, so you can test the refusal branches only.

## Reference

- [Withdraw from card](/platform/cards/withdraw-from-card)
- [Manage card status](/platform/cards/manage-card-status)
