diff --git a/docs/api/endpoints.md b/docs/api/endpoints.md index dfd619f2..9c7430a9 100644 --- a/docs/api/endpoints.md +++ b/docs/api/endpoints.md @@ -486,34 +486,87 @@ Authorization: Bearer sk-... } ``` -### Withdraw Funds +### Refund Balance -Withdraw balance as eCash. +Pay out the remaining balance and close the key. The payout goes to a Lightning address when one is given (in the request or stored on the key), otherwise a Cashu token is returned. ```http -POST /v1/wallet/withdraw +POST /v1/balance/refund Authorization: Bearer sk-... +Content-Type: application/json ``` -**Request Body:** +`/v1/wallet/refund` is a deprecated alias. + +**Request Body** (optional): ```json { - "amount": 5000, - "mint": "https://mint.example.com" + "lightning_address": "user@getalby.com" } ``` -**Response:** +**Parameters:** + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| `lightning_address` | string | No | Key's stored refund address | Lightning address or LNURL to pay. Overrides the stored address for this request. Resolved before any balance is debited. | + +**Response (Lightning):** ```json { - "cashu_token": "cashuAeyJ0...", - "amount": 5000, - "mint": "https://mint.example.com" + "refund_id": "3f9c1e2d8b7a4c6e9f0a1b2c3d4e5f60", + "status": "paid", + "recipient": "user@getalby.com", + "sats": "4500" } ``` +**Response (Cashu):** + +```json +{ + "refund_id": "3f9c1e2d8b7a4c6e9f0a1b2c3d4e5f60", + "status": "paid", + "token": "cashuAeyJ0...", + "sats": "4500" +} +``` + +The amount field is `sats` or `msats` depending on the key's refund currency. + +**Behaviour:** + +- The balance is debited and a refund claim is recorded before the payout is attempted. A key has at most one open claim at a time. +- If the payout fails cleanly, the claim is closed and the balance is restored. Retry the request. +- If the Lightning payment is dispatched but the mint cannot confirm the outcome, the request returns `502`, the balance stays withheld, and a background reconciler asks the mint until it answers. The balance is restored if the mint reports the payment unpaid. +- Calling again on a zero-balance key returns the last paid Lightning refund, or the previously issued Cashu token while it remains uncollected. + +**Errors:** + +| Status | Meaning | +|--------|---------| +| `400` | Invalid Lightning destination, no balance, or balance too small for the refund unit | +| `400` | Ongoing requests are still reserving balance on this key | +| `401` | Unknown key | +| `409` | Balance changed concurrently. Retry. | +| `409` | `refund_in_progress`: another refund claim for this key is still open | +| `410` | Previously issued Cashu refund token has been swept | +| `502` | Payment dispatched, outcome unconfirmed. Balance withheld pending reconciliation. Do not retry. | +| `503` | Mint unavailable. Balance restored. Retry later. | + +**X-Cashu refunds:** + +Requests paid per-call with an `X-Cashu` header get their change from this endpoint by sending the same header instead of `Authorization`: + +```http +POST /v1/balance/refund +X-Cashu: cashuAeyJ0... +``` + +Returns the change token in the body and in an `X-Cashu` response header. `404` if no matching request exists, `425` while the change is still being minted, `410` if it was swept. + ## Provider Discovery ## Admin Settings