API reference

Change where a printed QR code points, from your own systems. Create codes in bulk, read scan figures, and keep everything in step with whatever you already run — without anyone opening a dashboard.

Prefer to click than to read? Try any endpoint with your own token in the API explorer. For your tools rather than for you, there is an OpenAPI 3.1 spec and a Postman collection.

The thing worth knowing first

A dynamic QR code encodes a short link, not your destination. The symbol on the packaging never changes; what it resolves to is a row in a database. So repointing a code that is already in the world is a single request, and it takes effect for every copy of it at once — the recalled batch, the seasonal menu, the campaign that moved.

Authentication

Every request carries a bearer token. Create one under API tokens; it is shown once and stored only as a hash, so it cannot be recovered later.

curl https://www.lynkarr.com/api/v1/me \
  -H "Authorization: Bearer lyn1_your_token_here"

Every plan can call the API. The allowance is monthly and resets on the 1st:

The allowance is counted per company, not per token, so issuing more tokens does not raise it. Exhausting it returns 402 with a quota_exceeded code.

Scopes

A token holds exactly the scopes it was given. A write scope does not imply the matching read scope — being explicit means a token's permissions are what the list says, with nothing inferred.

ScopeAllows
codes:read List codes and read their settings.
codes:write Create codes and change where they point. This is what lets a printed code be redirected.
links:read List short links and their destinations.
links:write Create short links and change their destinations.
analytics:read Scan counts, geography, devices and timing.
cards:read List cards, read their details, and read the enquiries people have sent through them.
cards:write Create and edit cards, and publish or unpublish them.
pages:read List pages and read their content and settings.
pages:write Create and edit pages, and publish or unpublish them.
forms:read List forms, read their fields, and read what people have submitted. Submissions are your customers' own details, so grant this deliberately.
forms:write Create and edit forms, and publish or unpublish them.
media:read List files and folders with their names, types and sizes. Uploading is not offered to a token.
gs1:read List GS1 Digital Links and read what each one resolves to.
gs1:write Create and edit GS1 Digital Links and their resolutions.
campaigns:read List campaigns, their members and the tags in use.
campaigns:write Create and edit campaigns and tags, and move things in and out of them.
team:read List who is on the account, their roles and when they last signed in.
team:write Invite people, change their role and remove them. The most dangerous scope there is — a leaked token with this can take over the account — so only an owner can grant it, and even then it can never touch an owner or make anybody one.

Endpoints

MethodPathScope
GET /api/v1/me any Confirm a token works and see what it may do.
GET /api/v1/codes codes:read List QR codes. Paginated with limit and offset.
GET /api/v1/codes/:id codes:read One code, including its short link and scan count.
POST /api/v1/codes codes:write Create a code. Returns the URL to encode into the symbol.
PATCH /api/v1/codes/:id codes:write Change where a code points, rename it, or pause it.
POST /api/v1/codes/:id/archive codes:write Stop a code resolving. History is kept.
GET /api/v1/links links:read List short links.
POST /api/v1/links links:write Create a short link, optionally with a chosen ending.
GET /api/v1/analytics/codes/:id analytics:read Scans, unique visitors, daily series and countries.

Repointing a code

The request most integrations exist to make.

curl -X PATCH https://www.lynkarr.com/api/v1/codes/code_abc123 \
  -H "Authorization: Bearer lyn1_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/recall-notice"}'

The short link and the scan history are unchanged. Only the destination moves. A static code refuses this with 400, because its destination is encoded in the printed symbol and genuinely cannot change.

Creating a code

curl -X POST https://www.lynkarr.com/api/v1/codes \
  -H "Authorization: Bearer lyn1_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{"name": "Batch 4471", "url": "https://example.com/batch/4471"}'

The response includes encode — the value to render into the QR symbol. Rendering happens on your side or in our designer; the API stores the definition and owns the redirect.

Reading scans

curl "https://www.lynkarr.com/api/v1/analytics/codes/code_abc123?days=30" \
  -H "Authorization: Bearer lyn1_your_token_here"

Aggregated rather than raw: totals, unique visitors, a daily series and a country breakdown. Individual scan records are never returned, and no IP address is stored to return.

Errors

Every failure returns the same shape. Match on code, never on the sentence — the wording will be improved, the code will not change.

{
  "error": {
    "code": "forbidden",
    "message": "This token does not have the `codes:write` scope.",
    "docs": "https://www.lynkarr.com/docs/api"
  }
}
StatusCodeMeaning
400invalid_requestThe request was malformed or asked for something impossible.
401unauthorizedMissing, unknown, revoked or expired token.
402plan_requiredThe plan does not include this, or an allowance is used up.
403forbiddenThe token is valid but lacks the scope.
404not_foundNo such object for this company.
429rate_limitedToo many requests. Honour Retry-After.

A revoked token, an unknown token and one belonging to a suspended company all return the same 401. Distinguishing them would make this endpoint a way to test whether a guessed token exists.

Rate limit and quota

Two separate ceilings, because they fail for different reasons and are fixed in different ways.

120 requests per minute per token. Exceeding it returns 429 with Retry-After in seconds. This protects the platform rather than metering you — wait a moment and continue.

The monthly allowance above, per company. Exhausting it returns 402 and quota_exceeded; waiting will not help until the month turns over.

Every response carries both, so an integration can pace itself rather than discovering a ceiling by hitting it: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, and — on metered plans — Quota-Limit and Quota-Remaining.

Versioning

The version is in the path. /api/v1 will not change shape beneath you: fields may be added, but nothing that exists today will be removed or repurposed. A breaking change would arrive as /api/v2.

Create a token →