Refunds
A refund sends funds back to the customer: when an order is canceled, overpaid, or underpaid after expiration. You create one as a request via the API or in the dashboard.
Who sends the money
It depends on the request's executor field:
merchant: the payment went to your wallet (the usual case). Coinetic doesn't hold your funds, so you send the transfer to the customer yourself and record the transaction hash.platform: the payment went to a platform wallet. You only request the refund; a Coinetic operator verifies the address, approves and sends it.
Rules
- Only in the payment asset. If the customer paid USDT on TRON, they get USDT on TRON. There's no conversion.
- No more than was paid: see the invoice's
refundable_amount. Partial refunds are allowed, up to 20 open requests per invoice. - The address must be on the payment network. It's validated against the network's format (EVM uses the EIP-55 checksum). Coinetic's own addresses aren't accepted.
- A paid invoice stays paid. The amount refunded is tracked in
refunded_amount. - A refund permanently closes an unpaid invoice, even a partial one: the invoice becomes
cancelled, and top-ups will no longer pay for the order. Check the invoice status before submitting a request.
Create a request
POST /v1/refunds
Idempotency-Key: refund-ORDER-1001-1
Content-Type: application/json
{"invoice_id":"inv_x7k2…","amount_minor":"10500000","address":"TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE","reason":"Order ORDER-1001 canceled"}| Field | Required | Value |
|---|---|---|
invoice_id | yes | An invoice from your store |
amount_minor | yes | Smallest units as a string ("10500000" = 10.5 USDT at 6 decimals), or "full" for the entire available amount |
address | yes | The customer's address on the payment network |
reason | no | Reason, up to 500 characters |
Refunding from your wallet
- Send the request's
amountto the customer from your own wallet, in the payment asset and network (you pay the network fee). - Record the transaction hash:
POST /v1/refunds/{id}/executed
Idempotency-Key: refund-exec-ORDER-1001-1
Content-Type: application/json
{"tx_hash":"0x5c50…","ack_status_change":false}The request moves to reported. On EVM networks (Ethereum, BSC, Polygon, Base, Arbitrum), Coinetic finds the confirmed transaction on-chain, moves the request to sent and sends a refund.sent webhook. Bitcoin, Litecoin, TRON and Solana don't have automatic verification yet, so the request stays reported.
Changed your mind? Call POST /v1/refunds/{id}/cancel with a reason, and the amount becomes refundable again.
Statuses
| Status | Meaning |
|---|---|
requested | Request accepted |
approved | Approved by an operator (executor: platform only) |
reported | You've reported the hash; awaiting on-chain confirmation |
sent | Funds sent; tx_hash is the on-chain transaction |
rejected | Rejected or canceled; the reason is in reject_reason |
Rejections aren't sent as webhooks, so poll open requests on a schedule: GET /v1/refunds?status=requested.
In the sandbox
POST /v1/refunds/{id}/simulate runs the whole flow at once: the request becomes sent with a test tx_hash, and refund.sent fires. This route doesn't exist in production.