linkqrAPI for partners
Preview: planned API, not live yet

Connect your own tools

For agencies with their own field app, rota or CRM. Get the list of visits across the brands you manage and send back installs, stock checks, photos, removals and scans. Your team never has to open LinkQR, and your brands see it all in their dashboard straight away.

Getting started

  1. Make a key in Settings, Partner, API keys. It's shown once.
  2. Send it on every request: Authorization: Bearer lq_live_…
  3. Base address: https://api.linkqr.example/v1. JSON in and out, times in UTC (ISO 8601).

A key only reaches the brands you manage. Turn it off in Settings and it stops working at once. Up to 120 requests a minute per key; over that you get a 429 with Retry-After.

GET/visits?brand=&region=&limit=50

Locations that need a visit across the brands you manage, most urgent first: open stock reports, displays that didn't go up, never scanned, gone quiet.

Reply

{
  "visits": [
    {
      "location": { "id": "st067", "name": "Tesco Express, Hull Newland Avenue", "postcode": "HU5 2LH" },
      "codes": [
        { "code": "RTPXV", "brand": "Northfield Drinks", "project": "Summer Refresh", "item": "Poster",
          "status": "never", "reasons": [{ "kind": "never", "text": "Poster never scanned" }] }
      ]
    }
  ],
  "next": "cursor_2"
}

POST/installs

A display went up, or couldn't (with a reason: no-space, refused, damaged, not-arrived or other). A photo is required either way; upload it first.

Send

{ "code": "RTPXV", "outcome": "installed", "photo_id": "ph_81kd", "note": "Left of the door", "by": "Sam, Brightside Field", "at": "2026-09-25T10:42:00Z" }
{ "code": "X7U9B", "outcome": "failed", "reason": "no-space", "note": "Gondola end taken by a rival", "photo_id": "ph_82ma" }

Reply

{ "ok": true, "status": "live" }

POST/stock-checks

A shelf or display checked on a visit. Anything low or out opens a stock report, just like a shopper's.

Send

{ "code": "PPDCT", "photo_id": "ph_83zz", "items": [{ "product": "5012345678900", "status": "out" }, { "product": "5012345678917", "status": "ok" }] }

Reply

{ "ok": true, "reports_opened": 1 }

POST/removals

A display has been taken down. Its status becomes Taken down, or Removed early before the end date.

Send

{ "code": "3TFMJ", "at": "2026-09-25T16:05:00Z" }

Reply

{ "ok": true, "status": "removed" }

POST/scans

A scan from your own app, for example staff scanning with a handheld. Counted as a staff scan, not a shopper's.

Send

{ "code": "RTPXV", "at": "2026-09-25T10:40:00Z", "source": "staff" }

Reply

{ "ok": true, "counted": true, "first": true }

POST/photos

Upload a JPEG or PNG (multipart, up to 8 MB). We strip location and camera data. Use the id on installs and stock checks.

Send

Content-Type: multipart/form-data; field "file"

Reply

{ "photo_id": "ph_81kd" }

Errors

Errors come back as { "error": { "code": "unknown_code", "message": "No code RTPXQ for your brands" } } with a 4xx status: 400 for a bad request, 401 for a missing or turned-off key, 403 for a brand you don't manage, 404 for an unknown code, 429 when you're going too fast.

Questions? Talk to us.