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:
- Free — 1,000 requests per month
- Business — 5,000 requests per month
- Enterprise — unlimited
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.
| Scope | Allows |
|---|---|
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
| Method | Path | Scope | |
|---|---|---|---|
| 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"
}
}
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | The request was malformed or asked for something impossible. |
| 401 | unauthorized | Missing, unknown, revoked or expired token. |
| 402 | plan_required | The plan does not include this, or an allowance is used up. |
| 403 | forbidden | The token is valid but lacks the scope. |
| 404 | not_found | No such object for this company. |
| 429 | rate_limited | Too 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.