diff --git a/plans/names-codes/2026-10-21-store-api.md b/plans/names-codes/2026-10-21-store-api.md index deb1c987d5..89082bea12 100644 --- a/plans/names-codes/2026-10-21-store-api.md +++ b/plans/names-codes/2026-10-21-store-api.md @@ -367,7 +367,7 @@ A cancel that lost to settlement answers `200` with `status: paid`; the page re- ```json {"id": "t2Jk8RmQ4vXw9NcP3yLb6g", "version": 7, "moves": 0, "linksRefused": false, "phase": "committed", "labelHash": "0x…", "label": null, "owner": "0x…", "commitment": "0x…", "sealed": "…", "resolver": "0x…", "sponsor": "0x…", "chainId": 1, "tld": "simplex", - "years": 2, "duration": 69292800, "price": 10000, "fromBalance": 0, "balance": null, "commitTx": "0x…", "registerTx": null, + "years": 2, "duration": 69292800, "price": 10000, "fromBalance": 0, "balance": null, "latePayment": null, "commitTx": "0x…", "registerTx": null, "revealAfter": 1792828800, "revealBefore": 1792915140, "intentNonce": 0, "unread": [], "expiresAt": null, "error": null} ``` @@ -377,7 +377,8 @@ A cancel that lost to settlement answers `200` with `status: paid`; the page re- - `years`, `duration`: the term paid for; `duration` rebuilds the commitment on another browser. - `price`: what the order is worth in cents: the price paid, any part from a balance included, or after `/name` the new name's price, which caps a further move. 0 for a code. A paid order that ends `taken` keeps it as its balance. - `fromBalance`: the cents paid from another order's balance when the order was made (`/spend`, section 8); 0 when none. A move does not change it, so after a move to a cheaper name it can exceed `price`. -- `balance`: this order's balance (section 8), null when it has none: `{"amount": 10000, "held": false, "heldUntil": null, "refunded": 0}`. `amount`: the cents left to spend. `held`: an order's open invoice holds the balance; `heldUntil`: that invoice's `expiresAt`, else null. A holder whose invoice is past its expiry time with no money received reads as none (`held` false), as its invoice reads `expired`. `refunded`: the cents support refunded from it, over all its refunds. The holder is not named: whoever holds this order's link gets no other order's id from it. The page knows the holder from its own records (the order it made by `/spend`), or finds it with `find`. +- `balance`: this order's balance (section 8): null until its first credit, then always an object, with `amount` 0 once spent or refunded: `{"amount": 10000, "held": false, "heldUntil": null, "refunded": 0}`. `amount`: the cents left to spend. `held`: an order's invoice holds the balance. `heldUntil`: that invoice's `expiresAt` while no money has reached it, so the hold ends then unless paid; null when not held, and null while held by an invoice that money reached (it holds until its payment settles or the provider closes it, whatever the time; the page shows "in use by a payment being confirmed" and reads the view again). A holder whose invoice is past its expiry time with no money received reads as none (`held` false), as its invoice reads `expired`. `refunded`: the cents support refunded from it, over all its refunds. The holder is not named: whoever holds this order's link gets no other order's id from it. The page knows the holder from its own records (the order it made by `/spend`), or from `find`'s `heldBy` (section 8). +- `latePayment`: null, or `{"waiting": "confirming" | "crediting" | "support"}` while money on this closed `unpaid` order is not all credited to its balance (section 8, late payments). `confirming`: money received, not yet confirmed. `crediting`: confirmed, the credit not yet made (the poller's next pass, or a rate read that is failing for now). In both the page reads the view again. `support`: the credit will not come by itself (an invoice made under `HighSpeed`, an amount that could not be counted in units, a current rate below the floor, or unconfirmed money past the read window, once alerted); the page stops reading and tells the buyer to write to support with the reference. It turns null once all is credited, whatever it said before. - `commitTx`, `registerTx`: among the hashes sent since they were last cleared, the one mined with status 1, else the latest sent. Null when none, or when it was judged mined from chain state with no hash known. - `revealAfter`, `revealBefore`: the commit's block time plus the controller's `minCommitmentAge` and `maxCommitmentAge`. - `intentNonce`: `SimplexSponsor.nonces(owner)`, read only in `committed`, null otherwise. @@ -466,7 +467,7 @@ These need the owner code, so a link alone cannot use them. Each takes its limit Finds a name code's orders. Used by Check your code (the name code's verdict and Add to Your names), by an order link opened where the code is not stored, and after `409 order_exists`. - Message: `simplex.domains find `. -- `200 {"registrations": [{"registrationId": "…", "invoiceId": "…", "phase": "registered", "createdAt": "2026-10-21T09:15:00Z", "labelHash": "0x…", "sealed": "…"}]}`, newest first, one per registration of that owner, retargeted ones included: the 50 newest, and after them every older one holding a balance above 0, since a balance never expires. `invoiceId` is null for an order without an invoice: a code order, or one paid wholly from a balance. Balances are read from each order's view, not from `find`. `labelHash` and `sealed` let the page name every order with one request: it opens `sealed` with the code and checks the label's hash. +- `200 {"registrations": [{"registrationId": "…", "invoiceId": "…", "phase": "registered", "createdAt": "2026-10-21T09:15:00Z", "labelHash": "0x…", "sealed": "…", "balanceSource": null, "heldBy": null}]}`, newest first, one per registration of that owner, retargeted ones included: the 50 newest, and after them every older one holding a balance above 0, since a balance never expires. `invoiceId` is null for an order without an invoice: a code order, or one paid wholly from a balance. Balances are read from each order's view, not from `find`. `balanceSource`: the id of the order whose balance paid this one when it was made, else null. `heldBy`: the id of the order whose invoice holds this order's balance, else null, read as the view's `held` (an overdue holder with no money reads null). `find` proves the owner, so these ids go to nobody holding only a link; a browser that restored the name code learns from them which order a balance paid and which holds it. `labelHash` and `sealed` let the page name every order with one request: it opens `sealed` with the code and checks the label's hash. - Orders are signed by their owner (section 5), so only the owner code's own orders are listed. - `404 not_found` when the owner has none. `400 bad_request` for a wrong signer or a stale timestamp. `429 rate_limited` (find limit). @@ -497,7 +498,7 @@ A paid order whose name someone registered first keeps what it is worth as a bal - *Once:* each credit adds only the confirmed crypto (or, for Stripe, cents) not yet credited from that invoice, under the invoice's lock, with each credit numbered per invoice and unique, so a repeated, growing or reorganised report, or a second instance, never credits twice, and an unconfirmed payment that is replaced or dropped never credits. - *Which invoices:* a name invoice whose order is `unpaid` and not live, whatever the invoice's own status (a late `Settled` invoice reads `paid` while its order stays `unpaid`). - *When:* after the settlement that recorded the payment commits, by the poller, and again by the poller's pass (at its idle cadence) for any such invoice whose confirmed money is not all credited, so a crash or a failed rate read loses nothing. A cancel by the buyer reads no rate: its late money is credited by the poller. The rate read never runs under the invoice's lock, happens only when crypto is due, and is made once per currency pair per pass. - - *Pending and the alert:* money received but not confirmed (a mempool payment, Monero confirming with a zero figure) is pending and logged at info. The operator is alerted once per invoice, and again only when more money arrives, when money on a closed invoice is still not all credited and its payment was first seen longer ago than the poller's read window (`settleWindow`, about 72 hours). The alert names the crypto received, confirmed and credited (cents for Stripe), and its reason: unconfirmed money ("refund by hand only a transaction confirmed on chain that BTCPay no longer monitors; one still `Processing` there waits"), confirmed money waiting on a failing rate read ("do not refund; fix the rate read"), confirmed money waiting because the current rate is below the floor (naming both rates: "the coin's price fell by more than half since the invoice; the owner decides: credit at the current rate, or refund by hand"), or money that could not be counted in units ("check it at the provider"). Only one instance logs it, by a conditional write of the alert's mark. + - *Pending and the alert:* money received but not confirmed (a mempool payment, Monero confirming with a zero figure) is pending and logged at info. The operator is alerted once per invoice, and again only when more money arrives, when money on a closed invoice is still not all credited and its payment was first seen longer ago than the poller's read window (`settleWindow`, about 72 hours). The alert names the crypto received, confirmed and credited (cents for Stripe), and its reason: unconfirmed money ("refund by hand only a transaction confirmed on chain that BTCPay no longer monitors; one still `Processing` there waits"), confirmed money waiting on a failing rate read ("do not refund; fix the rate read"), confirmed money waiting because the current rate is below the floor (naming both rates: "the coin's price fell by more than half since the invoice; the owner decides: credit at the current rate, or refund by hand"), or money that could not be counted in units ("check it at the provider"). Only one instance logs it, by a conditional write of the alert's mark. The view's `latePayment` (section 6) tells the page which of these it is waiting on. - **Spent:** only by `/spend` (below), signed by the owner, for a new order of the same owner. When the balance covers the new name's price, the price is spent at once and the rest stays as balance. When it does not, all of it pays, and an invoice is made for the difference. - **Held:** while that invoice is open, the new order holds the balance: no other spend and no refund takes it. Settlement queues the new order and spends what it held, in one transaction. Whatever closes the invoice unpaid (a cancel, its expiry, the poller's sweep, a next order closing it as overdue, section 1) releases the hold in the transaction that closes the order. A payment that arrives after that is a late payment (section 1): it is credited to the closed order's own balance, and the released balance is not touched. A hold by an order whose invoice is past its expiry time with no money received reads as free (`held` false), and the next `/spend` of that balance closes that order first, in its own transaction, as section 1 closes an overdue order (below). A refund does not: it waits for the poller's sweep to close the holder. - **Refunded:** only by support, when the buyer writes with the order's reference (its invoice id, or its registration id for an order without an invoice). The operator command `//refund ` (task plan, T26) sets the balance to 0 and adds the cents to `refunded`, which counts every refund of the balance (one can be credited again later, by a late payment or a move); support then pays them back by hand, by the methods that paid them, which the command lists back through every balance the money came from. A held balance is never refunded, overdue holder or not: the command names the holder and its invoice's expiry, and support runs it again once the poller has closed the holder. There is no refund endpoint, no automatic refund, and no refund address given to the service.