9. The extension points, and how to ask for a new one
For: a builder whose need fits no rung of the ladder, or who needs to know which extension points exist today and which are still to come. Reference implementation: Request an extension point (the form) · for each live extension point, the chapter and sample named in the table below. The extension-point library — one page and one contract for each live extension point — is published with the kit at its first release.
What an extension point is
Most of what a customer asks for needs no new door: set it up in iVendNext (chapter 4), run your own service beside it (chapter 5), give the cashier a key (chapter 6) or ship your own records (chapter 7). An extension point is the door we build when none of those can do the job. It is a published place in iVendNext where your service, your page or your declared data takes part, with three things fixed in advance:
- the question we ask you, and the closed list of answers we accept;
- what happens when your service is down or too slow;
- what happens on a till with no network.
Because all three are written down before you build, the cashier is never left waiting on something we did not plan for. An extension point is never a place to change money after the cashier has seen it, and it never lets your code run inside the shop's own saves (chapter 3, the four rules).
When to use it
Go down the ladder first (chapter 3). Come here only when the rung above cannot do the job:
- Is the extension point you need already live? Use the table below and the chapter it names.
- Is it listed as specified or being specified? It is not available yet. We give no date. Plan the customer's project around the gap (chapter 16 lists what each gap costs), and tell us it matters to you with the request form, so it is built in the order the demand asks for.
- Is it not listed at all? Ask for a new one (below).
The extension points, by status
Each extension point is in exactly one of three states. The status is what has shipped, not what is planned.
Live
These have shipped in the product. Each is dormant until the customer's administrator switches it on.
| Extension point | What it lets you do | Where in the kit |
|---|---|---|
| Remote till key | Your HTTPS service answers a key the cashier presses: a message, or details added to the sale. | Chapter 6 · A till key · samples S1, S2, S6 |
| Event feed | Your app pulls its own queue of what changed in the shop (sales, customers, stock) and marks each item done. | Chapter 5 · Reading iVendNext's events reliably · ../tools/feed_client/ |
| Save rules | The shop declares a rule on a field, held at every save: a code's shape, a value worked out from others, no value twice, a field required when others are filled. | Chapter 7 (the save_rules kind) |
| Desk action | Your service answers a button on a record in iVendNext Desk, on the form or for the ticked rows of a list. | Chapter 13a · A button on a Desk record · S16 |
| Partner page | Your own page, framed on the till or in Desk, told who is looking at what by a signed context; on the till it may answer once. | Chapter 13a · Your own screen inside the shop's frame · S17 |
| Fiscal reader | An outside fiscal service's result for a sale, read from the fields it writes, so the receipt prints only when the tax result is back. | Chapter 11 · chapter 7 (the fiscal_readers kind) |
One more way in is live and is not an extension point: the manifest installer (chapter 7) installs your declared data, and the declarations of the live extension points above, switched off.
Specified, not yet released
Each of these has a written specification. None has shipped. Do not design a customer's go-live around any of them. A manifest that declares a scan source, a receipt block or a label layout is refused, naming what it waits on (chapter 7); the others have no manifest kind yet.
| Extension point | What it will let you do |
|---|---|
| Check before tender | A check before payment: your service allows the sale, refuses it with your own sentence, asks the cashier a question, asks for a manager's approval, or excludes some payment methods. |
| Wallet on the tender screen | A customer's own wallet or loyalty scheme, spent at the till as its own payment method: preview, authorise, reverse, refund. Chapter 11 says what that means today. |
| Scan resolver | A barcode your tables or service understand (unit barcodes, IMEI, pharmacy 2D codes), on the till, in Desk and on Handheld. |
| Capture on an event | A value captured when something is scanned or a customer is added. |
| Field vocabulary | Hide, relabel, require or add a column for a field at the till, per theme. |
| Receipt QR, fiscal marks and WhatsApp | A QR code and fiscal marks on the receipt, and a WhatsApp receipt. |
| Labels from the till and Handheld | Shelf and product labels sent through our print routes. |
| A host for sandboxed functions | The place on the server and on the till where a compiled function (chapter 8) runs, with the same answer offline. Until it ships there is nowhere to install a function. |
| Card-detail checks as a setting | A setting that makes card details required for a payment method. It needs the agreement of the engine team that owns the underlying code. |
| Pricing condition-and-adjuster | A price rule that promotions cannot express, computed by your own function and giving the same answer at preview, at booking and on an offline till. Design comes first, then the engine team's agreement. |
Being specified
We have decided to build these, and the specification is still owed. There is nothing to build against.
| Extension point | What it is for |
|---|---|
| Your own payment connector | A remote gateway contract (authorise, capture, void, refund, status, reconcile), so a partner's connector runs on its own server. Chapter 11 says what is true today. |
| A live price from your service before payment | A price or discount your service returns before payment (a carrier deal, say), within the shop's limits. Its specification is still owed. |
Asking for a new extension point, or for more from one
- Say what you need, not how. Describe the customer's need in business terms. A request that needs money changed in a hook, an override, a server script or in-tenant code by an outsider is read as a request for the need to be met another way.
- Check the catalogue above and the ladder. If a live extension point already does it, the answer says which.
- Fill in the request form. It has fourteen fields. The ones that matter most are the step (where in the sale it asks and who sees the answer), the data in, the answer out, what should happen when your service is down, how long the cashier may wait, and what should happen offline. A request that leaves out down, slow or offline comes back with a question.
- Send it. Where it goes is not open yet: the team repository does not exist (chapter 17), so submitting is not covered yet. Fill the form in anyway; it is also the page you hand your own customer.
What happens next. It is given an id. It is answered as one of four things: answered (a live door already meets it, and the answer says which), needs more (a question about a field), planned (an extension point is specified, or a live one extended, and you can follow it) or declined, with the reason. A planned extension point is written up in the shape of the form and joins this catalogue. The ladder class of a need changes only when the extension point ships. Requests of the same kind are collected, and the collection decides what is built next. We give no date.
What is refused, and why
- A request that breaks one of the four rules (chapter 3): money changed after the cashier has seen it, an override or patch of iVendNext, your code inside the customer's site, your own screens in Desk or on the till. These are declined with the reason, not planned.
- Product work dressed as an extension point. A change to what every cashier sees, or to the order of the steps, is product work, not something a partner extends. It is declined, with that reason.
- A declaration for an extension point that has not shipped. A manifest that declares a scan source, a receipt block or a label layout is refused, naming what it waits on.
- A sandboxed function. No extension point runs one yet, so every module is refused.
When your service is down, and when the till is offline
Every extension point states both before it ships. For the live ones:
| Extension point | Your service is down or slow | The till is offline |
|---|---|---|
| Remote till key | The cashier reads that your app could not finish; nothing is added; the sale goes on. No retry. | The key is dimmed. |
| Event feed | Nothing is lost: you pull, so your events wait until you are back. | An offline sale's events appear when the till syncs, possibly hours later. |
| Save rules | No service is called. | A write inside an offline sync is never refused, only flagged for review. |
| Desk action | The user reads "… did not answer in time. Check the record before you try again." It never claims nothing changed: your service may have written before it went quiet. | Desk is online by nature. |
| Partner page | A page that does not load in 10 seconds shows "… isn't answering." Nothing is added to the sale. | The key is dimmed. |
| Fiscal reader | The sale waits as pending and its receipt is held until the service answers or the back office does. | A sale made offline waits as pending, like any other, once the till syncs it. |
Technical notes
What the kit has proven
- The manifest installs the declarations of the live extension points. On the test shop a manifest installed a Desk action, a Desk-action and a page subscription, two save rules and a fiscal reader, all switched off. When the shop switched them on, the product accepted them (chapter 7).
- Two were walked on screen. The Desk action (S16) and the partner page (S17) were walked in a real browser on the test bench on 2026-10-07.
- A remote till key was pressed by a cashier on the till's own screen, the iVendNext POS app in a desktop browser on our test bench (S6's AI tip, 2026-10-07, frame
/pos?frame=terminal, POS app at8dc36aab8, row SHOTS2 runpp-20261007T105308Z-98631), answered over HTTPS with a certificate the bench's server trusted for the run. S1's Warranty key was pressed through the same endpoint from the bench's console as the cashier, not from a screen (row BUMP, G5b, runpp-20261007T014940Z-64695).
What it has not
- The extension-point library is not in the kit yet. There is no link to it here; it is published with the kit at its first release.
- The scoped event feed: the kit's client has been run against a stand-in for it only, not against the product's own (chapter 5).
- A press from a physical till device (a counter terminal or a phone, rather than the till app in a desktop browser) was not tried, and neither were the Desk screens for registering a till key.
- The manifest checker's refusal of a scan source, a receipt block or a label layout is read from its code; its own tests do not exercise it.
- Nothing in the specified or being-specified lists has run anywhere. They are written down, not built.
Sources
- Where each status comes from. Live is read from the extension-point library at the POS app's
developmentbranch (commit21c7512, 2026-10-07): its table lists exactly the six above, each with a page and a contract. The manifest installer row is the manifest checker's list of declarable kinds (tools/manifest/validate.py,KINDS_V2). Specified, not yet released is the programme's written catalogue of extension points built ahead of demand, minus the five that have shipped (the sixth, the remote till key, is not in it) and two engine items; the checker'sPOINT_KINDStable is where the three declaration kinds are refused. Being specified is the two entries of that catalogue still owed a specification. - Not listed on purpose. Two engine-side items (narrowing the feed's grant, and default permissions on two record types) are product work on the underlying engine, not extension points a partner uses, so they have no row here.
- What "live" does not mean. Live means shipped and dormant until configured. It does not mean every example in the kit has run against it; the sections above say which have.
- Request form.
../feedback/point_request.md, fourteen fields. - Names. The record the shop's administrator fills in for most of these is a Retail Extension Subscription; its call log is the Retail Extension Log; a sandboxed module's record is a Retail Extension Module.
See also
3. The ladder and the four rules · 5. Outside apps and the event feed · 6. Till keys · 7. Manifests · 11. Payments, fiscal, hardware · 16. Possible, not possible, limits · 17. Submitting, support, feedback