iVendNextDevelopers Request a sandbox

Making the integration user for a connected app — the recipe

A connected app signs in to a shop's iVendNext from outside, with an API key: a warranty service, a bin-location service, a marketplace bridge. This recipe shows how the shop gives that app its own user, holding only the rights it needs. It is for partners, and for our own Custom Development team. Reference implementation: the integration user the two sample services use (samples/s1_warranty/service/, samples/s2_bins/service/).

When to use it. Rung 2 of the build ladder: a connected app. Try configuration first (pricing rules, promotions, print formats, sale details, permissions). If the job really needs your own server, every connected app gets its own user, made this way. A till key hosted inside the shop, an embedded app and a manifest do not need one: they run as the cashier, the person booking the sale, or nothing at all.

The rule in one line. One connected app = one desk user = one user licence, holding one narrow role. The shop decides which apps get a user, what each may do, and when to switch one off.

Steps

The shop's administrator does these in iVendNext Desk.

  1. Make a role for this app alone (Desk → Role → New, then Role Permissions Manager). Give it only what the app reads and writes. The bin-location sample's role, for example:

    Record type Rights
    Item, Customer, Warehouse, Sales Invoice, POS Invoice, Bin (stock balances), POS Profile read
    Comment read, create
    Stock Entry read, write, create, submit
    Serial No; Serial and Batch Bundle read, write, create (+ submit on the bundle) — only if the app books serialised stock
    the app's own record types (from its manifest) read, write, create — granted by the manifest itself

    Do not start from an existing role such as Stock User: it carries far more than your app needs.

  2. Make one user for the app (Desk → User → New):

    • an e-mail that names the app, e.g. bins-service@yourshop.example;
    • tick Is Desk User. iVendNext refuses a user that is neither a desk user nor a POS user, so there is no API-only kind;
    • give it only the role from step 1;
    • set no password. The user never signs in to Desk: only its API key is used.
  3. Generate its API key and secret (User → Settings → API Access → Generate Keys). The secret is shown once. Put it straight into your service's secret store. Every request then carries:

    Authorization: token <api key>:<api secret>
    
  4. Know what the key can do. On a product before 2026-09-30, every desk user, the app's user included, also held iVendNext's Workspace Manager role. That role lets a user change the shared Desk workspaces. With it, the key could put content on a shared workspace that runs in the browser of whoever opens it, an administrator included. So on such a product a connected app's key can do what an administrator can. Since 2026-09-30 only a System Manager gets that role, so an app's user holding only the role from step 1 does not have it; the manifest installer refuses an integration user given it (guide/07_manifests.md). What the key can do is the shop's choice when it connects the app. Keep the key in a secret store, never in code or chat, and rotate it at any doubt (step 6).

  5. Prove the key, and prove its limits:

    curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: token $KEY:$SECRET" \
      "$BASE/api/resource/Item?limit_page_length=1"          # 200
    curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: token $KEY:$SECRET" \
      "$BASE/api/resource/Journal%20Entry?limit_page_length=1" # 403: outside the role
    curl -s -o /dev/null -w '%{http_code}\n' "$BASE/api/resource/Item?limit_page_length=1"  # 403: no key
    

    The request collection checks the same two refusals (files 17_refused_outside_role and 18_refused_without_key). Run it with curl and jq only: BASE=… KEY=… SECRET=… bash api/collection/run.sh.

  6. Rotate or revoke the key. To rotate it (a person who saw it leaves, or on a schedule), press Generate Keys again. The old secret is refused (401) at once, and the new one works (200). Update your service's secret store in the same change. To switch the app off, the shop deletes the user, or generates new keys and keeps the secret to itself. Disabling the user is not enough: its key still signs in.

What is refused, and why

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

The user does not change either. If the key is revoked or rotated without your service knowing, every call answers 401. Alert on it, and do not retry it in a loop. Till sales made offline reach you when the till syncs, through your webhooks (recipes/webhook_receiver.md).

What we would like to improve

Technical notes

What was proven where

Tests

This page in the kit