> For the complete index of the 402pay docs, see [llms.txt](https://developer.402pay.co/llms.txt).

# Refunds, returns and disputes

Send refunds from your wallet, return funds you don't accept, and keep disputes rare.

There's no refund endpoint and no `refunded` status. Payments go straight to your wallet, and money never moves on an API key, so a refund is a send from your wallet that you make yourself. This guide covers where to send it, how much, and how to keep a record.

## Where to send it

| The customer paid | Send the refund to |
| --- | --- |
| Crypto from their own wallet | `method.from_address`, the address the transfer came from, on the same network. Confirm it with the customer first. |
| Crypto from an exchange | An address the customer gives you. The address the transfer came from often belongs to the exchange, not to them. |
| Card, Apple Pay or Google Pay | An address the customer gives you. Card payments arrive as crypto on the selected network, so the refund goes out in crypto, not back to the card. |

> A transfer to the wrong address or network can't be undone. Ask the customer to confirm the address, coin and network before you send.

## How much to send

- A whole crypto payment: `method.amount` of `method.asset` is what arrived. For a card payment, `amount_received` is what the customer paid, in the payment's currency.
- An overpayment's excess: `method.overpaid_amount`, in `method.asset`.
- A late or wrong-network transfer you don't want to accept: everything that arrived, from the payment that `needs_review`.
- Coin prices move after a payment. Decide whether you refund the same coin amount or the same value in your currency, and say which in your terms.

## Send the refund

From a wallet created or imported in 402pay, open Wallet in the dashboard, choose the coin and network, and send. Each payment landed at its own address, so the send draws on the addresses holding the coin, signed in your browser with your encryption password. From an external wallet, send in your own wallet app, then record the send in the dashboard with its transaction hash, so your history matches. API keys can't send, so refunds go out from the dashboard, which checks each one as [send from the wallet](https://developer.402pay.co/api/wallet/transactions/create.md) describes.

Every send pays a network fee. A token send, such as USDC on Polygon, pays it in the network's own coin, POL on Polygon, so keep a little of it in the wallet; without enough, the send fails with `insufficient_fee_funds`. Estimate the fee first.

Estimate the network fee, cURL:

```bash
curl "https://dash.402pay.co/api/v1/wallet/fee-estimates?network=polygon" \
  -H "Authorization: Bearer $PAY402_SECRET_KEY"
```

Estimate the network fee, Node.js:

```js
const response = await fetch("https://dash.402pay.co/api/v1/wallet/fee-estimates?network=polygon", {
  headers: {
    Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}`,
  },
});
const { data } = await response.json();
```

Estimate the network fee, Python:

```python
import os

import requests

response = requests.get(
    "https://dash.402pay.co/api/v1/wallet/fee-estimates?network=polygon",
    headers={
        "Authorization": f"Bearer {os.environ['PAY402_SECRET_KEY']}",
    },
)
data = response.json()["data"]
```

## Keep a record

The payment stays `succeeded` after a refund, so your own records are the source of truth. Add the refund to the payment's metadata, which merges by key, so you can filter refunded payments later.

Note the refund on the payment, cURL:

```bash
curl -X PATCH "https://dash.402pay.co/api/v1/payments/pmt_QI02vLdJGd48hBbg" \
  -H "Authorization: Bearer $PAY402_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "metadata": {
      "refund_status": "refunded",
      "refund_tx_hash": "0x5a1f9c3e8b7d6a2f4c0e9b8a7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c"
    }
  }'
```

Note the refund on the payment, Node.js:

```js
const response = await fetch("https://dash.402pay.co/api/v1/payments/pmt_QI02vLdJGd48hBbg", {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    metadata: {
      refund_status: "refunded",
      refund_tx_hash: "0x5a1f9c3e8b7d6a2f4c0e9b8a7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c"
    }
  }),
});
const { data } = await response.json();
```

Note the refund on the payment, Python:

```python
import os

import requests

response = requests.patch(
    "https://dash.402pay.co/api/v1/payments/pmt_QI02vLdJGd48hBbg",
    headers={
        "Authorization": f"Bearer {os.environ['PAY402_SECRET_KEY']}",
    },
    json={
        "metadata": {
            "refund_status": "refunded",
            "refund_tx_hash": "0x5a1f9c3e8b7d6a2f4c0e9b8a7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c"
        }
    },
)
data = response.json()["data"]
```

Give the send itself a note, up to 280 characters, when you make it in the dashboard, or later with `PATCH /wallet/transactions/{id}`.

Note the send, cURL:

```bash
curl -X PATCH "https://dash.402pay.co/api/v1/wallet/transactions/wtx_Q7vXk2Lp9RmT4sYb" \
  -H "Authorization: Bearer $PAY402_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "note": "Refund for order_1042"
  }'
```

Note the send, Node.js:

```js
const response = await fetch("https://dash.402pay.co/api/v1/wallet/transactions/wtx_Q7vXk2Lp9RmT4sYb", {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    note: "Refund for order_1042"
  }),
});
const { data } = await response.json();
```

Note the send, Python:

```python
import os

import requests

response = requests.patch(
    "https://dash.402pay.co/api/v1/wallet/transactions/wtx_Q7vXk2Lp9RmT4sYb",
    headers={
        "Authorization": f"Bearer {os.environ['PAY402_SECRET_KEY']}",
    },
    json={
        "note": "Refund for order_1042"
    },
)
data = response.json()["data"]
```

## Late and wrong-network transfers

A payment that `needs_review` already has its funds in your wallet. If you don't want to [accept it](https://developer.402pay.co/api/payments/accept.md), send the funds back the same way as a refund. The payment stays `needs_review`, so record what you did in its metadata, such as `review` set to `returned`, and filter those out of your review queue.

## Disputes

A crypto transfer can't be reversed by the sender, so crypto payments have no chargebacks. Cardholders can still dispute a card payment with their bank, and you'll be asked for evidence. A clear description of what customers are buying, and your refund policy shown before they pay, keep disputes rare.
