---
title: "Know what a bank deposit costs"
description: "Find out which bank deposits into a customer's account carry a Gravv fee, on which rail, who pays the fee and where to find it."
---
This recipe shows which bank deposits into a customer's account carry a Gravv fee, on which rail, who pays the fee and where to find it. It is for a US payroll platform whose business customers fund their Gravv USD account by wire from their own bank.

**Status.** Available.

## Money example

1. Your customer Acme Ltd has an active USD account. You show its routing and account numbers.
2. Acme's bank sends a 2,500.00 USD wire.
3. Gravv credits the account the full **2,500.00 USD** and sends `transfer.inflow.completed`, or `transfer.inflow.deposit_settled` if the account converts deposits to USDC.
4. Gravv bills the wire deposit fee on your plan to **your business**, from your main account or on your monthly invoice. Gravv does not take it out of Acme's 2,500.00 USD.

## Before you start

- The account is `active` and has its bank details. To set this up, see [Share account details and receive a deposit](/recipes/accounts-v2/share-account-details-and-receive-a-deposit).
- You have registered your webhook URL in the Dashboard.

## Find out what is required

The fee depends on the rail the money arrives on, and on the kind of account. Your prices per rail are in your pricing plan. The API does not return them.

| Rail | Account that converts deposits to stablecoin | Other bank-held account | NGN account |
| :-- | :-- | :-- | :-- |
| ACH | Charged | Not charged today | Not applicable |
| Wire, RTP, SWIFT, SEPA, FPS | Charged, at that rail's price | Charged, at that rail's price | Not applicable |
| Rail not known | Charged a flat deposit fee | Not charged | Not applicable |
| Local NGN transfer | Not applicable | Not applicable | Not charged |

- Gravv bills the fee to your business and does not deduct it from the deposit.
- Gravv does not refund the fee if the deposit later fails or is reversed.

## Steps

### 1. Credit the customer when the deposit lands

Follow [Share account details and receive a deposit](/recipes/accounts-v2/share-account-details-and-receive-a-deposit#2-credit-the-customer-when-the-deposit-lands). On an account that converts deposits, `transfer.inflow.deposit_settled` and `inflow.onchain.completed` describe **one** deposit, so credit the customer once.

### 2. Find the fee

Find the deposit row with the `transaction_id` from the webhook, then the fee row for the same customer, as in [See a deposit arrive](/recipes/transactions/see-a-deposit-arrive#4-find-the-fee).

<CodeGroup>
```bash title="cURL"
curl --request GET \
     --url 'https://api.gravv.xyz/v1/transactions?customer_id=121ae3e6-03a6-4966-a13b-ca7fd644de2f&transaction_type=fee_charge' \
     --header 'Api-Key: <API_KEY>'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/transactions?customer_id=121ae3e6-03a6-4966-a13b-ca7fd644de2f&transaction_type=fee_charge", {
  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/transactions?customer_id=121ae3e6-03a6-4966-a13b-ca7fd644de2f&transaction_type=fee_charge",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

## What can go wrong

| Response | Why | Fix |
| :-- | :-- | :-- |
| No bank details on the account | The account is not `active` yet | Finish the account application |
| `transfer.inflow.awaiting_approval` | Your account holds deposits for approval | Approve or reject it in the Dashboard. The API has no approve route |
| `transfer.inflow.payout_failed` or `transfer.inflow.compensated` | Crediting failed, or was reversed | Contact support with the `transaction_id`. Gravv does not refund the deposit fee |
| No webhook, but the payer says they sent the money | The payer used wrong bank details, the bank is still processing, or your server missed a webhook | Check webhook history with `event_type=transfer`, and check the details the payer used |
| No fee row | Your plan has no fee for that rail, or the fee is on your monthly invoice | No action needed |

## Webhooks you will receive

- `transfer.inflow.awaiting_approval`, only on accounts that hold deposits for approval.
- Then `transfer.inflow.completed` or `transfer.inflow.deposit_settled`. On accounts that convert deposits, `inflow.onchain.completed` comes with it.
- On a failure, `transfer.inflow.payout_failed` or `transfer.inflow.compensated`.

## Testing in sandbox

Simulate a deposit on each `rail` (`ach`, `wire`, `rtp`, `swift`, `sepa`, `fps`) to see that rail's fee on your sandbox billing. Each new `Idempotency-Key` makes a new deposit, and `amount` is a string.

<CodeGroup>
```bash title="cURL"
curl --request POST \
     --url https://api.gravv.xyz/v2/accounts/simulate/deposit \
     --header 'Api-Key: <API_KEY>' \
     --header 'Idempotency-Key: 0252c0da-374a-4eac-bf9a-2203e6881143' \
     --header 'Content-Type: application/json' \
     --data '
{
  "account_id": "416e99b0-e13e-413e-bdaa-ea00a01d616f",
  "amount": "2500.00",
  "rail": "wire"
}
'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v2/accounts/simulate/deposit", {
  method: "POST",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
    "Idempotency-Key": "0252c0da-374a-4eac-bf9a-2203e6881143",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "account_id": "416e99b0-e13e-413e-bdaa-ea00a01d616f",
    "amount": "2500.00",
    "rail": "wire"
  }),
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.post(
    "https://api.gravv.xyz/v2/accounts/simulate/deposit",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
        "Idempotency-Key": "0252c0da-374a-4eac-bf9a-2203e6881143",
        "Content-Type": "application/json",
    },
    json={
        "account_id": "416e99b0-e13e-413e-bdaa-ea00a01d616f",
        "amount": "2500.00",
        "rail": "wire",
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

The response `{"data":{"accepted":true,"reference":"…","state":"pending"},"error":null}` does not mean the account is credited. Wait for the webhook. With a live key, this call returns 403.

## Reference

- [Simulate a deposit](/api-reference/accounts-v2/post-v2-accounts-simulate-deposit)
- [List transactions](/api-reference/transactions/get-v1-transactions)
- [Receive deposits](/platform/accounts/receive-deposits)
