From e765c61684f4ec9bea1722c3d018cf9f7461ade9 Mon Sep 17 00:00:00 2001 From: shum Date: Thu, 22 Oct 2026 14:24:44 +0000 Subject: [PATCH] store: document //refund and the speed policy --- apps/simplex-store-service/README.md | 74 +++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/apps/simplex-store-service/README.md b/apps/simplex-store-service/README.md index 8b644ef6a4..b66c6c8c56 100644 --- a/apps/simplex-store-service/README.md +++ b/apps/simplex-store-service/README.md @@ -128,6 +128,15 @@ The BTCPay API key needs four permissions, each scoped to the one store: `canmodifyinvoices` so `POST /api/invoice/:id/cancel` can invalidate an invoice at BTCPay rather than only in this store. +**Do not set `speed_policy = HighSpeed` when names are sold** (`[names]` configured). Under it +BTCPay can mark a payment `Settled` with no confirmation, so the service never credits crypto that +reaches a name invoice after the invoice closed: the money stays pending, the poller alerts about it +once it is older than its read window (about 72 hours), and support settles it by hand. The service +judges each invoice by the policy it was created with, so changing the setting later credits nothing +that arrived under `HighSpeed`. With `MediumSpeed` (the template's value) or a slower policy, late +money is credited to the order's balance once confirmed, at the lower of the invoice's rate and the +rate when it is credited. + Give the service a BTCPay store of its own, and a Stripe account of its own if card payments are on. The poller lists every invoice and payment intent of the last three days or so, and one it did not create and cannot read is reported in a warning once an hour until it falls out of that window. @@ -766,7 +775,8 @@ were already given out, and the command answers with an error. A multi-use code be revoked, which stops the uses that remain. Core parses `//...` into `CustomChatCommand` and leaves it to the service's `preCmdHook`, which is -why issuing codes lives in the service rather than in core. +why issuing codes lives in the service rather than in core. `//refund`, the other command of this +console, is in [Refunding a name balance](#refunding-a-name-balance). ### From the group @@ -776,7 +786,8 @@ and above, `/revoke ` for admins and owners. `months` is 1 to 255, `uses` `count` 1 to 100; a value outside these gets the usage reply. The name forms are `/issue name [years ]` and `/bulk name [years ] count `, with the bounds of `//issue name`; a name code issued in the group is single-use and `free`. `/revoke` -takes badge codes only: withdraw a name code with `//revoke` in `--run-cli` mode. A member's role +takes badge codes only: withdraw a name code with `//revoke` in `--run-cli` mode. The group has no +`/refund`. A member's role is checked as the service last saw it, so a command sent by a moderator just demoted or removed can still run if it reaches the service first; revoke any code the service posts for them after the change. `uses` above 1 makes a multi-use code, tracked by a group message showing its remaining uses and the time @@ -835,3 +846,62 @@ join link still works and its messages hold every code posted there. The configured `display_name` and `description` apply only to the group the service creates. Editing them later is logged as not applied and changes nothing. + +## Refunding a name balance + +A paid name order keeps its money as a balance when it ends `taken` (another buyer registered the +name first), when it moves to a cheaper name (the difference), and when a payment reaches its invoice +after the invoice closed. The buyer spends a balance on another name from Your names, or asks for it +back: the page tells them to write to chat@simplex.chat with the order's reference, which is its +invoice id, or its registration id for an order without an invoice. Nothing is refunded +automatically, and the service never learns where to send money. Support records each refund in +`--run-cli` mode, as `//revoke` of a name code: + +``` +//refund +//refund +``` + +1. Run `//refund ` with the reference the buyer sent. It records nothing and answers the + balance, what paid for it and the command that refunds it: + + ``` + Order : balance $100.00 (credited $100.00, refunded $0.00). Paid by: order : $100.00 by btc on invoice . To record its refund: //refund 10000 + ``` + + `Paid by` starts at this order and follows every balance the money came through back to the + first order: each order with what its invoice paid and by which method (`card`, `btc` or + `xmr`), the part paid from the balance of the next order listed, and, marked `late`, money + credited after its invoice closed. +2. Run the command the answer ends with. The cents must equal the whole balance: a refund zeroes it, + and part of a balance is never refunded. If the balance changed since step 1, by a spend or a + late credit, nothing is recorded and the answer gives the balance now; start again at step 1. +3. The answer, `Recorded a refund of $100.00 for order . Refund it now, by: …`, repeats the + chain. Pay the money back now, by the methods it lists: a card payment as a refund in the Stripe + Dashboard, crypto to an address the buyer gives, at that day's rate, since the balance is in US + cents. The refund is recorded first so that the buyer cannot spend the money while it is paid + back. The service logs each recorded refund at info with the order's registration id and the + cents. + +A balance that an open order holds is never refunded: that order is buying another name with it and +its invoice is waiting for the difference. The command names the order and its invoice's expiry +instead: + +- `its invoice open until