Browse the docs

Start here

Connecting stores

How a store lets your POS in with a one-time code, and how it leaves.

A store decides who gets its orders. Your POS can only see a store after the store's owner lets it in, with a one-time code.

The flow

  1. The store owner opens the Scanimart retailer app, goes to Settings → POS software → Connect your POS and generates a code. It looks like K7Q2-M9XP, works once, and expires after 15 minutes.
  2. They type it into your POS — wherever your software asks for it.
  3. Your server exchanges it, with a key that covers every connected store:
Shell
curl -X POST https://api.scanimart.com/v1/connections/claim \
  -H "Authorization: Bearer $SCANIMART_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"code": "K7Q2-M9XP"}'
JSON
{
  "object": "store_link",
  "id": "5b0f…",
  "store": { "object": "store", "id": 1042, "name": "Fresh Mart", "city": "Bengaluru", "…": "…" },
  "connected_at": "2026-10-08T10:15:00+05:30"
}

Store this store.id against your own record of the shop. A store.connected webhook is also sent, so a backend that did not handle the claim itself still hears about it.

Claiming a code for a store you are already connected to returns the existing connection (200 instead of 201), so retrying a claim is safe.

A wrong, used or expired code fails with invalid_connection_code. Ask the owner for a fresh one — never retry the same code in a loop.

A store-scoped key cannot claim codes: it gets 403 key_scope_insufficient, and the code is not spent. If your software runs on the shop's PC, have it pass the code to your server to claim, then create a store-scoped key for the new store and install that on the PC.

What a connection covers

GET /v1/stores lists only this POS company's active connected stores in the API key's mode. It is not a directory of all Scanimart stores. A store-scoped key returns only its own store, and a company with no active connections receives an empty list. Other POS companies' stores and disconnected stores are excluded.

From the moment of connection, you receive the store's order and sale events and may call its order, inventory and sales endpoints.

The order endpoints also reach back before that: GET /v1/stores/{store_id}/orders and GET …/orders/{order_id} return the store's Scanimart orders from before it connected you, as well as the ones since. Events and sales do not. No webhooks are sent for anything that happened before connected_at, and GET /v1/events and GET …/sales start there. Tell the store, in your terms with it, that your software can read its earlier orders too.

A store can be connected to more than one company — for example a billing POS and a separate inventory tool. Each sees the same orders. Only one can accept a given order: whoever acts first wins, and the other gets order_not_in_required_state.

Disconnecting

Either side can end it:

  • The store owner disconnects you in the retailer app (Settings → POS software), which lists every POS connected to the store.
  • You call POST /v1/stores/{store_id}/disconnect — for example when the shop cancels its subscription with you.

Either way you get store.disconnected, events for that store stop, and calls for it are answered 404 store_not_found — the same answer as for a store that does not exist, so ids cannot be probed. In the retailer app, the store's POS software list moves you under Disconnected. Revoke any store-scoped key you made for it. Reconnecting takes a new code.

In the sandbox

The sandbox has no retailer app. Set up sandbox in the dashboard creates your test store and connects it for you, so you can skip straight to orders. Test the claim call itself in live, with a friendly store, before you roll out.