Skip to content
Skip the menu

Guides

Refunds

Refund a paid order from your server, see what is taken back from the player, and read what a refund could not recover.

View as Markdown

On this page

What a refund does

A refund cancels one paid order. In one step, GameCoin:

  1. gives the money back to the buyer (simulated in the test environment);
  2. takes back the currency the order delivered, with one refund_clawback ledger entry per currency;
  3. takes back the items the order delivered, as far as the player still owns them;
  4. sets the order to refunded.

Only a server can refund, with the secret key. A browser cannot, and the SDK has no refund. A studio member can also refund from the order's page in the dashboard (« Rembourser la commande », in French).

Refund an order

POST/orders/{orderId}/refund

The only field is an optional reason, up to 500 characters. An empty body means {}.

LangageLanguage
curl -X POST "https://gamecoin.apilow.com/api/v1/orders/6ac419fbdbe02af6c99c3d47/refund" \
  -H "Authorization: Bearer $GAMECOIN_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"customer request"}'
Answer
{
  "id": "6ac419fbdbe02af6c99c3d47",
  "playerId": "6ac419fa60e877541898f38d",
  "status": "refunded",
  "pack": { "sku": "gems-500", "name": "Bag of gems" },
  "amountCents": 499,
  "currency": "EUR",
  "country": "FR",
  "vatRateBp": 2000,
  "vatCents": 83,
  "netCents": 416,
  "createdAt": "2026-10-05T21:43:23.065Z",
  "paidAt": "2026-10-05T21:43:42.641Z",
  "fulfilledAt": "2026-10-05T21:43:42.641Z",
  "refundedAt": "2026-10-05T21:44:07.009Z",
  "creatorCode": null
}

Only a fulfilled order can be refunded. Any other state answers 409 CONFLICT: an order still pending was never paid, and a refunded one is already done. A refund cannot be done twice, so a second call changes nothing.

An unknown order id answers 404 NOT_FOUND. The reason is kept with the order and is visible in the dashboard.

If the call fails halfway

A refund has no idempotency key. It is protected by the state of the order instead. After a network error or a 5xx, read the order before you try again:

LangageLanguage
curl "https://gamecoin.apilow.com/api/v1/orders/6ac419fbdbe02af6c99c3d47" \
  -H "Authorization: Bearer $GAMECOIN_SECRET_KEY"

If the status is refunded, the refund went through. If it is still fulfilled, send it again.

What is taken back

The refund takes back what the order delivered, not what the player has today. The order remembers, for each currency, how many paid and bonus coins it credited. The pack gems-500 credited 500 paid and 50 bonus gems, so a refund takes back 550.

If the pack included items, the refund removes them, up to what the player still owns. A player who already drank the potion of a starter pack has none left to remove: the refund removes nothing more, and the quantity never goes below zero.

When the player already spent the coins

The order credited 550 gems. If the player has spent some, the wallet cannot give 550 back. What happens depends on a setting of your game (« Après un remboursement » in the dashboard, which is in French):

SettingDashboard nameWhat the refund does
Allow a debt (default)« Autoriser une dette »Takes back all 550. The balance goes below zero: the player is in debt.
Stop at zero« S'arrêter à zéro »Takes back only what is left. The balance never goes below zero. The rest is a shortfall, and you bear it.

With the default, a player who bought gems-500, spent 400, and was refunded, ends at -400:

The wallet after the refund
{
  "playerId": "6ac419fa60e877541898f38d",
  "balances": [
    { "currency": "gems", "paid": -400, "bonus": 0, "total": -400 },
    { "currency": "gold", "paid": 0, "bonus": 0, "total": 0 }
  ]
}

A debt behaves like this:

  • The player cannot spend until the debt is paid: a spend answers INSUFFICIENT_FUNDS with available: 0.
  • Every credit pays the debt first. If you grant 100 gems to this player, the balance becomes -300, not 100. A pack they buy pays the debt first too.
  • The balance is never negative in bonus; the debt sits in paid.

The two settings are a choice between two risks. A debt protects you from a player who buys, spends, then asks for a refund. Stopping at zero never shows a negative balance, but the coins that player spent are your loss.

Read what was taken, and what was not

Every refund writes refund_clawback entries in the ledger, one per currency, each with the ref.orderId of the order. The order's own purchase_credit entries have the same ref.orderId and tell what was delivered. Compare the two:

LangageLanguage
# The ledger entries of the player: keep those whose ref.orderId is the order,
# then add up purchase_credit (delivered) and refund_clawback (taken back) for each currency.
curl "https://gamecoin.apilow.com/api/v1/players/ext%3Auser-42/ledger?limit=100" \
  -H "Authorization: Bearer $GAMECOIN_SECRET_KEY"
  • With allow a debt, shortfall is always 0: everything was taken. Read the debt in the wallet, as a negative total.
  • With stop at zero, taken is smaller than credited. The difference is the shortfall.

In the dashboard, the order's page shows the shortfall (« Manque à la reprise »), the debt, and the entries the order caused (« Écritures liées »). The API does not return a shortfall field: use the comparison above.

Refund and the ledger together

Nothing is deleted. After a refund, the ledger of the player holds the purchase, the spends, and the clawback. Their sum is the balance, debt included.

EntrypaidDeltabonusDeltabalanceAfter.total
purchase_credit+500+50550
spend (400 gems)−350−50150
refund_clawback−5500−400

Where next