iVendNextDevelopers Request a sandbox

6. Till keys

A cashier presses the AI tip key on the till, and the hint shows in the till's own sheet

A cashier presses a partner's AI tip key during a sale; the partner's server answers, and the hint shows in the till's own sheet (sample S6).

A till key lets the cashier see an answer from your server during a sale: a warranty, a member's balance, where an item sits. This chapter is for a developer who builds the service behind that key.

Reference implementation: A till key, step 6 (the answer you give, from your own server); an AI-written hint is the same key with a model behind it, in A till key that asks an AI model · samples ../samples/s1_warranty/ (core.py, remote/) and ../samples/s2_bins/ (core.py, service/, and the key declared in manifest.json).

When to use it

Rung 3 of the ladder (chapter 3), after configuration (chapter 4) and an outside app (chapter 5). The cashier taps a key; the till calls your HTTPS service with the sale as it stands; you answer with a message to read, or sale details the cashier applies. It never changes a price, a total or a payment. Python that runs inside the shop is not a partner route (chapter 3).

Steps

  1. Know what the till sends you. It is read-only:

    {"sale_ref": "…", "store": "<warehouse>", "pos_profile": "…", "company": "…", "currency": "ZAR",
     "operator": "<user>", "customer": "<customer or null>",
     "lines": [{"item_code": "…", "qty": 1.0, "uom": "Nos", "luid": "l0"}]}
    

    ⛔ No prices, no totals, no serial numbers. If you need a serial, ask the cashier on your own page, or read the booked sale afterwards (chapter 5). The till sends what is on the device, so never grant value on this context alone.

  2. Write your logic once, as a function with nothing from iVendNext in it: the context and your own reference data in, the answer out. Record a few real contexts and test against them without a shop:

    python3 -m unittest discover -s samples/s1_warranty/tests -p 'test_core.py'
    
  3. Answer in the till's closed vocabulary. Two kinds, nothing else:

    {"message": {"title": "Warranty", "body": "PP-WRC-PHONE: 24 months; AIRPODS-3: 12 months", "level": "success"}}
    {"sale_attributes": [{"sale_attribute": "<an active Sale Attribute>", "attribute_value": "…"}]}
    

    The limits: title up to 60 characters, body up to 280, level info, success or warning, at most 20 sale details. One bad part refuses the whole answer: the till never applies half. Keep a long answer inside the cap yourself (the warranty sample ends with "… and N more").

  4. Put it behind HTTPS and check every call. The service is a few lines around your function:

    def answer(context):          # the whole binding
        codes = sorted({l["item_code"] for l in context.get("lines") or []})
        terms = {**MY_TERMS, "item_group": tenant.item_groups(codes)}   # your own store + one API read
        return core.warranty_answer(context, terms)
    

    What each call looks like, and what you check:

    • Each call is one POST with the headers X-iVendNext-Timestamp, X-iVendNext-Signature and X-iVendNext-Request-Id, and the body {"app", "key", "returns", "context"}.
    • Verify it against the raw body before parsing. The signature is the base64 HMAC-SHA256 of <timestamp>.<raw body> with the secret you and the shop share. A timestamp more than five minutes from your clock is refused.
    • Answer a JSON object of at most 64 KB, well inside the time to answer.
    • Only HTTPS is called, with the certificate checked against your host name. An address that resolves to a private network is refused unless the shop's site is set to allow it (for test sites).
  5. The shop registers the key. A System Manager opens Retail Remote App Key in Desk and adds one record per key: your name as the partner, an app name, the key, its label, what it may return, your HTTPS address, the signing secret, and the time to answer: 3 seconds unless raised. Design for 3. The ceiling depends on who sets it: the record itself accepts at most 10 seconds (this step, filled in by hand in Desk), and a manifest may declare at most 5 (our checker refuses more). The administrator ticks the customer's consent to send the listed sale details to your address. Then the store switches the key on in POS Studio → the theme → Apps → tick the key → Save. The counter layout shows it; the phone layout shows no key. If your package is a manifest, it can declare the key too (chapter 7): it is installed switched off, with consent not given.

    A till key's record in Desk: switched on, message only, the partner's HTTPS address

    A till key's record in Desk: switched on, it may return a message only, and it calls the partner's HTTPS address (sample S6; the picture is cut above the signing secret).

  6. Test your service's failures before the shop does. Make it slow, make it fail, send the wrong shape. Check that the cashier would read one of the three sentences below and nothing would be added to the sale. The warranty sample's fault routes (remote/wrapper.py) do this; they are on only when its test runner starts it, and your copy deletes them.

What is refused, and why

When your service is down, and when the till is offline

Every failure ends in a refusal in words, with nothing added to the sale. These are the words the released key publishes:

What happens The cashier reads
Your service takes longer than the time to answer, or trickles its reply "Warranty did not answer in time. Nothing was added to the sale."
Down, a non-2xx status, a redirect, a bad signature "Warranty could not finish. Nothing was added to the sale."
Not JSON, oversize, a malformed or partial answer, an undeclared kind "Warranty answered in a way this till cannot use. Nothing was added to the sale."

Offline: the key works only online. On an offline till it is dimmed, and the sale goes on without it.

Technical notes

Sources for the plain layer

What the kit has proven

What it has not

The pictures

See also

3. The ladder and the four rules · 5. Outside apps and the event feed · 7. Manifests · 13. AI on iVendNext

This page in the kit