Docs / Integration

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
HTTP
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"}
FieldRequiredValue
invoice_idyesAn invoice from your store
amount_minoryesSmallest units as a string ("10500000" = 10.5 USDT at 6 decimals), or "full" for the entire available amount
addressyesThe customer's address on the payment network
reasonnoReason, up to 500 characters

Refunding from your wallet

  1. Send the request's amount to the customer from your own wallet, in the payment asset and network (you pay the network fee).
  2. Record the transaction hash:
HTTP
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

StatusMeaning
requestedRequest accepted
approvedApproved by an operator (executor: platform only)
reportedYou've reported the hash; awaiting on-chain confirmation
sentFunds sent; tx_hash is the on-chain transaction
rejectedRejected 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.