API for utviklere

Koble qsy til systemene du allerede har.

Et REST-API som snakker JSON. Kassesystemet, bookingløsningen eller nettbutikken lager kortlenker med QR-kode, bytter hvor de peker og henter skann-tall. API-et følger med Bedrift.

For integratorer

Laget for systemer som eier mange koder.

Tenk deg et restaurantsystem med én QR-kode per bord på tjue restauranter. Slik ser det ut med qsy:

  • Én mappe og én nøkkel per restaurant. En nøkkel kan låses til én mappe. Den ser bare sine egne koder, og en feil i én integrasjon når aldri de andre.
  • Dine id-er, ikke våre. Gi hver kode din egen external_id, for eksempel bordnummeret i kassen. Ett PUT-kall lager koden om den mangler og oppdaterer den om den finnes.
  • Trygt å prøve igjen. Send en Idempotency-Key når du oppretter. Faller nettet midt i kallet, gir et nytt forsøk samme svar i stedet for en kopi.
  • Koden på trykk står stille. Du bytter destinasjon så ofte du vil. Slugen endres aldri, og en slettet slug gis aldri til en annen lenke.

Kom i gang

En nøkkel i en header.

Alle kall går til https://api.qsy.no/v1. Send nøkkelen i hver forespørsel:

HTTP
Authorization: Bearer qsy_live_…

Nøkler lager du under Konto, API-nøkler, når kontoen har Bedrift. Du ser nøkkelen én gang. Vi lagrer bare et SHA-256-avtrykk og de første tegnene (qsy_live_ og seks til), så du kjenner den igjen i lista. Mister du den, lager du en ny. En nøkkel kan få utløpsdato etter 30, 90 eller 365 dager.

Gå til API-nøkler

Tilgang per nøkkel

Du krysser av hva hver nøkkel kan gjøre. Nye nøkler har bare lesetilgang avkrysset fra start.

Tilgang per nøkkel
ScopeGir tilgang til
links:readLese lenker og mapper, og hente QR-koden til en lenke.
links:writeLage, endre og slette lenker og mapper.
styles:readLese lagrede stiler.
analytics:readLese skann-statistikk.
qr:writeLage statiske QR-koder (POST /v1/qr).

Hurtigstart

Fra nøkkel til QR-kode på trykk, i fire steg.

Eksemplene bruker curl og leser nøkkelen fra miljøvariabelen QSY_API_KEY.

  1. 01

    Lag en nøkkel

    Under Konto, API-nøkler. Kryss av links:write og analytics:read, og velg eventuelt en mappe nøkkelen skal låses til. Legg nøkkelen i miljøet ditt:

    shell
    export QSY_API_KEY="qsy_live_…"
  2. 02

    Lag en lenke med din egen id

    external_id knytter koden til bordet i systemet ditt. Idempotency-Key gjør at et nytt forsøk etter et brudd ikke lager en kopi. Svaret har id, short_url og qr_encoded_url.

    curl
    curl -X POST "https://api.qsy.no/v1/links" \
      -H "Authorization: Bearer $QSY_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: 0e6c4b8a-2f1d-4d7e-9b3a-5c8f1e2d4a6b" \
      -d '{
      "destination_url": "https://bistro-nord.no/meny?utm_source=qr&utm_medium=table",
      "title": "Table 12 menu",
      "folder": "Bistro Nord/Tables",
      "external_id": "pos-table-12",
      "metadata": {
        "table": 12,
        "location": "grunerlokka"
      },
      "style_id": "9c8b7a6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"
    }'
  3. 03

    Hent QR-koden som SVG

    Vektor, klar for trykk. Koden peker på kortlenka, så du kan bytte destinasjon senere uten å trykke på nytt.

    curl
    curl "https://api.qsy.no/v1/links/3f6c2a9e-8b1d-4c5e-9a7f-2d4b6e8c1a3f/qr" \
      -H "Authorization: Bearer $QSY_API_KEY" \
      -o qr.svg
  4. 04

    Les skann-tallene

    Datoene er kalenderdager i Europe/Oslo. Er analysen nede, svarer API-et 503, aldri med nuller.

    curl
    curl "https://api.qsy.no/v1/links/3f6c2a9e-8b1d-4c5e-9a7f-2d4b6e8c1a3f/stats?from=2026-10-19&to=2026-10-25" \
      -H "Authorization: Bearer $QSY_API_KEY"

Senere bytter du destinasjon med PATCH /v1/links/{id}, eller synker hele bordlista med PUT /v1/links/by-external-id/{external_id}.

Begreper

Det du trenger å vite før du bygger.

Mapper og mappe-låste nøkler

Mapper ordner lenkene, opptil 50 per konto og fem nivåer dypt. Lager du en lenke uten mappe, havner den i «Via API». Med en sti som «Bistro Nord/Bord» finnes eller lages hvert nivå, uten duplikater. Er taket nådd, får du 409 folder_limit_reached, aldri en stille plassering et annet sted.

En nøkkel som er låst til en mappe, ser mappa som en toppmappe. Lenker andre steder finnes ikke for den (404). Nye lenker havner i mappa, og nøkkelen kan ikke flytte eller slette sin egen mappe. Sletter du mappa, trekkes nøkkelen tilbake.

Upsert med external_id

external_id er din id, opptil 128 tegn og unik per konto. PUT /v1/links/by-external-id/{external_id} lager lenka (201) om den mangler, og oppdaterer bare feltene du sender (200) om den finnes. Kallet tåler å bli gjentatt. metadata er et fritt JSON-objekt på opptil 4 KB som følger lenka.

curl
curl -X PUT "https://api.qsy.no/v1/links/by-external-id/pos-table-12" \
  -H "Authorization: Bearer $QSY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "destination_url": "https://bistro-nord.no/meny?utm_source=qr&utm_medium=table",
  "title": "Table 12 menu",
  "folder": "Bistro Nord/Tables"
}'

Idempotency-Key

Gjelder POST /v1/links og POST /v1/links/bulk. Samme nøkkel og samme body innen 24 timer gir det lagrede svaret tilbake, med headeren Idempotent-Replayed: true. Samme nøkkel med en annen body gir 409 idempotency_key_reused. Bruk en ny UUID per operasjon.

Stiler og SVG

Stiler lager du i studioet, og GET /v1/styles gir deg id-ene. Sender du style_id når du lager en lenke, kopieres stilen inn i lenka. Endrer du stilen senere, beholder eksisterende lenker sin. qr_config sendt direkte vinner over style_id. QR-kodene leveres som SVG. Trenger du PNG, lager du det fra SVG-en.

Feil

Hver feil har samme form: en fast maskin-kode, en melding på engelsk og en request_id. Statusen hører alltid til koden. Ved valideringsfeil lister details hvert felt som er feil. Driftsproblemer gir 500 eller 503, aldri 401 eller 403.

422 · application/json
{
  "error": {
    "code": "validation_error",
    "message": "The request contains invalid fields.",
    "details": [
      {
        "field": "external_id",
        "code": "too_big",
        "message": "external_id must be 1-128 characters."
      }
    ],
    "request_id": "req_5f2c9a0e7b1d4c3a8e6f0b2d"
  }
}
Feilkoder
KodeStatusBetyr
bad_request400Ugyldig JSON, en body som ikke er et objekt, en ugyldig Idempotency-Key eller ingenting å endre.
key_expired401Nøkkelen har passert utløpsdatoen. Lag en ny.
unauthorized401Nøkkelen mangler, har feil form, er ukjent eller er trukket tilbake.
forbidden403Kontoen har ikke API-tilgang, nøkkelen mangler scope, eller en mappe-låst nøkkel prøver å flytte eller slette sin egen mappe.
not_found404Finnes ikke, tilhører en annen konto eller ligger utenfor nøkkelens mappe.
conflict409Forespørselen kolliderer med det som er lagret.
duplicate_external_id409En annen lenke på kontoen bruker denne external_id.
folder_exists409En mappe med samme navn finnes der fra før. details.id er den mappa.
folder_limit_reached409Taket på antall mapper er nådd. details har limit og used.
folder_not_empty409Mappa har innhold. Send ?force=true for å flytte innholdet ett nivå opp.
idempotency_key_in_use409Et kall med samme Idempotency-Key pågår fortsatt.
idempotency_key_reused409Idempotency-Key er brukt før med en annen body.
link_limit_reached409Planens tak for aktive lenker er nådd. details har limit og used.
unsupported_media_type415Bodyen må sendes med Content-Type: application/json.
validation_error422Ett eller flere felt er ugyldige. details lister dem.
rate_limited429For mange kall. Vent så mange sekunder som Retry-After sier.
internal_error500Feil hos oss. Prøv igjen, og send oss request_id om det varer.
service_unavailable503En tjeneste vi bruker er midlertidig nede. Prøv igjen etter Retry-After.

Grenser for antall kall

600 kall i minuttet per nøkkel og 1200 per konto, i et glidende vindu. Hvert svar har X-RateLimit-Limit, X-RateLimit-Remaining og X-RateLimit-Reset (Unix-tid i sekunder). Ved 429 venter du så mange sekunder som Retry-After sier.

HTTP
X-Request-Id: req_5f2c9a0e7b1d4c3a8e6f0b2d
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 599
X-RateLimit-Reset: 1793008860

Når en endring er ute

Kortlenkene serveres fra kanten, nær den som skanner. Skrivekall svarer med edge_synced: true når endringen er ute med en gang, og false når den kommer i løpet av sekunder. En helt ny lenke kan da svare «finnes ikke» et lite øyeblikk.

Tidssone, paginering og CORS

Statistikk regnes i kalenderdager i Europe/Oslo. Tidsstempler er ISO 8601 i UTC. Lister pagineres med next_cursor til den er null. API-et har ingen CORS. Det er laget for server til server, så nøkkelen skal aldri ligge i en nettleser eller app.

Grenser

Tallene, samlet ett sted.

Antall aktive lenker følger planen og står på prissiden. Resten gjelder alle kontoer med API-tilgang.

Tallene, samlet ett sted.
GrenseVerdi
Kall per minutt per nøkkel600
Kall per minutt per konto1 200
Aktive nøkler per konto20
Lenker per side, standard50
Lenker per side, maks100
Operasjoner per bulk-kall100
QR-størrelse, minst (px)128
QR-størrelse, størst (px)2 048
QR-størrelse, standard (px)1 024
Tegn i en statisk QR-kode2 953
Tegn i title200
Tegn i destination_url4 096
Tegn i external_id128
Byte i metadata (kompakt JSON)4 096
Mapper per konto50
Nivåer i mappetreet5
Tegn i et mappenavn60
Timer en Idempotency-Key huskes24
Tegn i en Idempotency-Key255
Dager i statistikk-vinduet, standard30
Land i statistikken (topp)5

Personvern

Tall, ikke personer.

Statistikken teller skann per dag, enhet, kilde, land og tid på døgnet. Vi lagrer aldri IP-adresser. Land vises bare når det er nok skann til at ingen kan pekes ut, og API-et gir ingen byer. Dataene ligger i EU.

Referanse

Alle endepunkter.

Referansen lages fra OpenAPI-spesifikasjonen, den samme fila som testene holder lik koden. Beskrivelsene er på engelsk, som API-et.

Last ned spesifikasjonen (OpenAPI 3.1, JSON)

Lenker

get/v1/links/by-external-id/{external_id}Hent lenke med external_id

The link with this external_id. A link outside the key's folder → 404.

Scope links:read

Parametre

GET /links/by-external-id/{external_id} · Parametre
NavnITypePåkrevdBeskrivelse
external_idstistringjaYour identifier, percent-encoded. Avoid "/" in external ids.
expandspørring"qr_config"neiComma-separated. Only qr_config is supported; unknown values → 422.
Eksempel · curl
curl "https://api.qsy.no/v1/links/by-external-id/pos-table-12" \
  -H "Authorization: Bearer $QSY_API_KEY"
Svar · 200 · application/json
{
  "id": "3f6c2a9e-8b1d-4c5e-9a7f-2d4b6e8c1a3f",
  "slug": "k7qm2x",
  "short_url": "https://qsy.no/k7qm2x",
  "qr_encoded_url": "HTTPS://QSY.NO/K7QM2X",
  "destination_url": "https://bistro-nord.no/meny?utm_source=qr&utm_medium=table",
  "title": "Table 12 menu",
  "active": true,
  "use_shortlink": true,
  "folder_id": "0b2d4f6a-8c1e-4a3b-9d5f-7e9a1c3b5d7f",
  "folder_path": "Bistro Nord/Tables",
  "external_id": "pos-table-12",
  "metadata": {
    "table": 12,
    "location": "grunerlokka"
  },
  "created_at": "2026-10-25T10:00:00.000Z",
  "updated_at": "2026-10-25T10:00:00.000Z",
  "edge_synced": null
}
put/v1/links/by-external-id/{external_id}Opprett eller oppdater med external_id (upsert)

Missing → created with the POST /links rules (destination_url required) → 201. Exists → updated with the PATCH rules (only the fields you send change; an empty object changes nothing) → 200. external_id in the body is optional but must match the path. Naturally idempotent, so no Idempotency-Key is needed. If the id is used by a link outside a folder-scoped key's folder → 409 duplicate_external_id.

Scope links:write

Parametre

PUT /links/by-external-id/{external_id} · Parametre
NavnITypePåkrevdBeskrivelse
external_idstistringjaYour identifier, percent-encoded. Avoid "/" in external ids.

Body · UpdateLinkRequest

PUT /links/by-external-id/{external_id} · Body
NavnTypePåkrevdBeskrivelse
destination_urlstringneihttp(s) URL, or a mailto:, tel:, sms:, WIFI: or vCard destination. UTM goes straight into the URL and is stored as sent. On redirect, qsy.no rewrites utm_medium=qr (case-insensitive) to utm_medium=qsy.no-shortlink when the shared short link is opened (lowercase path, no ?src=qr); QR scans keep qr, other media and parameters are never changed, and utm_medium is never added.
titlestring | nullneiHuman-readable name. Trimmed; empty → null.
activebooleanneiInactive links stop redirecting. Only active links count towards the plan limit.
use_shortlinkbooleanneitrue (default): the QR code encodes the short link, so the destination can be changed after printing. false: the QR code encodes destination_url directly (no redirect, no scan statistics). WIFI: and vCard destinations are always encoded directly.
qr_configQrConfig | nullneiFull QR style. Wins over style_id. Stored on the link (replaced as a whole on update).
style_idstring · uuid | nullneiCopy a saved style from your account into the link. Input only (copy model): later edits to the style do not change existing links, and style_id is never returned.
folder_idstring · uuid | nullneiTarget folder. Must be visible to the key. On update, null moves the link to the account root (account-wide keys only).
folderstring | nullneiFolder path such as "Bistro Nord/Tables". Each level is found (case-insensitive) or created, relative to the key's root. Max 5 levels, each 1-60 characters. Send folder_id or folder, not both.
external_idstring | nullneiYour own identifier (POS table id, product id …). Unique per account. On update, null clears it.
metadataobjectneiFree-form JSON object, at most 4096 bytes as compact JSON. Replaced as a whole on update (send {} to clear).
Eksempel · curl
curl -X PUT "https://api.qsy.no/v1/links/by-external-id/pos-table-12" \
  -H "Authorization: Bearer $QSY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "destination_url": "https://bistro-nord.no/meny?utm_source=qr&utm_medium=table",
  "title": "Table 12 menu",
  "folder": "Bistro Nord/Tables"
}'
Svar · 200 · application/json
{
  "id": "3f6c2a9e-8b1d-4c5e-9a7f-2d4b6e8c1a3f",
  "slug": "k7qm2x",
  "short_url": "https://qsy.no/k7qm2x",
  "qr_encoded_url": "HTTPS://QSY.NO/K7QM2X",
  "destination_url": "https://bistro-nord.no/meny?utm_source=qr&utm_medium=table",
  "title": "Table 12 menu",
  "active": true,
  "use_shortlink": true,
  "folder_id": "0b2d4f6a-8c1e-4a3b-9d5f-7e9a1c3b5d7f",
  "folder_path": "Bistro Nord/Tables",
  "external_id": "pos-table-12",
  "metadata": {
    "table": 12,
    "location": "grunerlokka"
  },
  "created_at": "2026-10-25T10:00:00.000Z",
  "updated_at": "2026-10-25T10:00:00.000Z",
  "edge_synced": true
}

Mapper

get/v1/foldersList mapper

All folders visible to the key as a flat list sorted by path. A folder-scoped key sees its folder as a top-level folder (parent_id null).

Scope links:read

Eksempel · curl
curl "https://api.qsy.no/v1/folders" \
  -H "Authorization: Bearer $QSY_API_KEY"
Svar · 200 · application/json
{
  "folders": [
    {
      "id": "7a1e4c2b-5d3f-4e6a-8b9c-0d1e2f3a4b5c",
      "name": "Bistro Nord",
      "parent_id": null,
      "path": "Bistro Nord",
      "link_count": 2,
      "subtree_link_count": 14,
      "created_at": "2026-10-25T10:00:00.000Z",
      "updated_at": "2026-10-25T10:00:00.000Z"
    },
    {
      "id": "0b2d4f6a-8c1e-4a3b-9d5f-7e9a1c3b5d7f",
      "name": "Tables",
      "parent_id": "7a1e4c2b-5d3f-4e6a-8b9c-0d1e2f3a4b5c",
      "path": "Bistro Nord/Tables",
      "link_count": 12,
      "subtree_link_count": 12,
      "created_at": "2026-10-25T10:00:00.000Z",
      "updated_at": "2026-10-25T10:00:00.000Z"
    }
  ]
}
post/v1/foldersOpprett mappe

Max 50 folders per account, nested at most 5 levels. A sibling with the same name (case-insensitive) → 409 folder_exists with its id in details.

Scope links:write

Body · CreateFolderRequest

POST /folders · Body
NavnTypePåkrevdBeskrivelse
namestringjaTrimmed. Must not contain "/". Unique among siblings (case-insensitive).
parent_idstring · uuid | nullneiOmitted or null → the key's root.
Eksempel · curl
curl -X POST "https://api.qsy.no/v1/folders" \
  -H "Authorization: Bearer $QSY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Bistro Nord"
}'
Svar · 201 · application/json
{
  "id": "7a1e4c2b-5d3f-4e6a-8b9c-0d1e2f3a4b5c",
  "name": "Bistro Nord",
  "parent_id": null,
  "path": "Bistro Nord",
  "link_count": 0,
  "subtree_link_count": 0,
  "created_at": "2026-10-25T10:00:00.000Z",
  "updated_at": "2026-10-25T10:00:00.000Z"
}
get/v1/folders/{id}Hent mappe

One folder with link counts.

Scope links:read

Parametre

GET /folders/{id} · Parametre
NavnITypePåkrevdBeskrivelse
idstistring · uuidjaFolder id. A value that is not a UUID → 404.
Eksempel · curl
curl "https://api.qsy.no/v1/folders/7a1e4c2b-5d3f-4e6a-8b9c-0d1e2f3a4b5c" \
  -H "Authorization: Bearer $QSY_API_KEY"
Svar · 200 · application/json
{
  "id": "7a1e4c2b-5d3f-4e6a-8b9c-0d1e2f3a4b5c",
  "name": "Bistro Nord",
  "parent_id": null,
  "path": "Bistro Nord",
  "link_count": 2,
  "subtree_link_count": 14,
  "created_at": "2026-10-25T10:00:00.000Z",
  "updated_at": "2026-10-25T10:00:00.000Z"
}
patch/v1/folders/{id}Gi nytt navn til eller flytt mappe

Rename and/or move. A folder-scoped key can rename its own folder but not move it (403).

Scope links:write

Parametre

PATCH /folders/{id} · Parametre
NavnITypePåkrevdBeskrivelse
idstistring · uuidjaFolder id. A value that is not a UUID → 404.

Body · UpdateFolderRequest

PATCH /folders/{id} · Body
NavnTypePåkrevdBeskrivelse
namestringnei
parent_idstring · uuid | nullneiMove the folder. null → the key's root. Cannot move into itself or a subfolder.
Eksempel · curl
curl -X PATCH "https://api.qsy.no/v1/folders/7a1e4c2b-5d3f-4e6a-8b9c-0d1e2f3a4b5c" \
  -H "Authorization: Bearer $QSY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Bistro Nord Grünerløkka"
}'
Svar · 200 · application/json
{
  "id": "7a1e4c2b-5d3f-4e6a-8b9c-0d1e2f3a4b5c",
  "name": "Bistro Nord Grünerløkka",
  "parent_id": null,
  "path": "Bistro Nord Grünerløkka",
  "link_count": 2,
  "subtree_link_count": 14,
  "created_at": "2026-10-25T10:00:00.000Z",
  "updated_at": "2026-10-25T10:00:00.000Z"
}
delete/v1/folders/{id}Slett mappe

An empty folder is deleted. A folder with subfolders or links → 409 folder_not_empty with counts, unless ?force=true: then its contents move up one level and no link is ever deleted. API keys limited to the deleted folder are revoked. A folder-scoped key cannot delete its own folder (403).

Scope links:write

Parametre

DELETE /folders/{id} · Parametre
NavnITypePåkrevdBeskrivelse
idstistring · uuidjaFolder id. A value that is not a UUID → 404.
forcespørring"true" | "false"nei"true" moves contents up one level instead of refusing.
Eksempel · curl
curl -X DELETE "https://api.qsy.no/v1/folders/7a1e4c2b-5d3f-4e6a-8b9c-0d1e2f3a4b5c" \
  -H "Authorization: Bearer $QSY_API_KEY"
Svar · 200 · application/json
{
  "id": "7a1e4c2b-5d3f-4e6a-8b9c-0d1e2f3a4b5c",
  "deleted": true,
  "contents_moved_to": null
}

QR-koder

get/v1/links/{id}/qrHent QR-koden til en lenke (SVG)

Renders the link's QR code as SVG. It encodes qr_encoded_url: the short link, or the destination only for use_shortlink=false and WIFI:/vCard links. No query parameter can change what the code points to. Style overrides apply to this rendering only; nothing is stored.

Scope links:read

Parametre

GET /links/{id}/qr · Parametre
NavnITypePåkrevdBeskrivelse
idstistring · uuidjaLink id. A value that is not a UUID → 404.
formatspørring"svg"neiOnly svg.
sizespørringintegerneiPixel size of the SVG coordinate system, clamped to 128-2048 (default 1024; invalid → 1024).
style_idspørringstring · uuidneiRender with a saved style instead of the link's own.
qr_configspørringstringneiURL-encoded JSON QrConfig, full or partial (merged over the defaults). Wins over style_id.
Eksempel · curl
curl "https://api.qsy.no/v1/links/3f6c2a9e-8b1d-4c5e-9a7f-2d4b6e8c1a3f/qr" \
  -H "Authorization: Bearer $QSY_API_KEY" \
  -o qr.svg
Svar · 200 · image/svg+xml
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">…</svg>
post/v1/qrLag statisk QR-kode (SVG)

Encodes data literally: no short link, no tracking, nothing stored. For labels, WiFi and contact cards that must work without a redirect. The code can never be changed after printing.

Scope qr:write

Body · StaticQrRequest

POST /qr · Body
NavnTypePåkrevdBeskrivelse
datastringjaEncoded literally. You build the WIFI:, BEGIN:VCARD or geo: string yourself.
type"url" | "wifi" | "vcard" | "text" | "geo"jaDocuments the content; it does not change what is encoded.
qr_configQrConfigneiFull style. Wins over style_id.
style_idstring · uuidneiA saved style on your account.
format"svg"neiOnly SVG. Rasterise it yourself if you need PNG.
sizeintegerneiOut-of-range values are clamped, invalid values fall back to 1024.
Eksempel · curl
curl -X POST "https://api.qsy.no/v1/qr" \
  -H "Authorization: Bearer $QSY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "data": "WIFI:T:WPA;S:BistroNord-Guest;P:velkommen2026;;",
  "type": "wifi",
  "style_id": "9c8b7a6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
  "size": 1024
}' \
  -o qr.svg
Svar · 200 · image/svg+xml
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">…</svg>

Statistikk

get/v1/links/{id}/statsHent skann-statistikk for en lenke

Aggregated scans for one link. Dates are calendar days in Europe/Oslo. Counters only: no IP addresses, no cities, no personal data. If analytics are unavailable the API answers 503 (never zeros).

Scope analytics:read

Parametre

GET /links/{id}/stats · Parametre
NavnITypePåkrevdBeskrivelse
idstistring · uuidjaLink id. A value that is not a UUID → 404.
fromspørringstring · dateneiYYYY-MM-DD (Europe/Oslo). Default: 29 days before today (a 30-day window).
tospørringstring · dateneiYYYY-MM-DD (Europe/Oslo), inclusive. Default: today. Must not be before from, and the window can be at most 1096 days.
Eksempel · curl
curl "https://api.qsy.no/v1/links/3f6c2a9e-8b1d-4c5e-9a7f-2d4b6e8c1a3f/stats?from=2026-10-19&to=2026-10-25" \
  -H "Authorization: Bearer $QSY_API_KEY"
Svar · 200 · application/json
{
  "link_id": "3f6c2a9e-8b1d-4c5e-9a7f-2d4b6e8c1a3f",
  "from": "2026-10-19",
  "to": "2026-10-25",
  "granularity": "day",
  "total": 412,
  "all_time": 3871,
  "series": [
    {
      "bucket": "2026-10-19",
      "count": 48
    },
    {
      "bucket": "2026-10-20",
      "count": 51
    },
    {
      "bucket": "2026-10-21",
      "count": 44
    },
    {
      "bucket": "2026-10-22",
      "count": 57
    },
    {
      "bucket": "2026-10-23",
      "count": 79
    },
    {
      "bucket": "2026-10-24",
      "count": 91
    },
    {
      "bucket": "2026-10-25",
      "count": 42
    }
  ],
  "breakdowns": {
    "device": {
      "mobile": 398,
      "desktop": 6,
      "tablet": 8,
      "unknown": 0
    },
    "source": {
      "qr": 401,
      "link": 11,
      "unknown": 0
    },
    "country": [
      {
        "country": "NO",
        "count": 371
      },
      {
        "country": "SE",
        "count": 22
      },
      {
        "country": "DE",
        "count": 19
      }
    ],
    "daypart": {
      "night": 9,
      "morning": 61,
      "day": 158,
      "evening": 184
    }
  }
}

Stiler

get/v1/stylesList stiler

Saved QR styles on the account, newest first. Styles are made in the qsy studio; the API only reads them. Account-level: not limited by folder scope.

Scope styles:read

Eksempel · curl
curl "https://api.qsy.no/v1/styles" \
  -H "Authorization: Bearer $QSY_API_KEY"
Svar · 200 · application/json
{
  "styles": [
    {
      "id": "9c8b7a6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
      "name": "Bistro Nord",
      "qr_config": {
        "mode": "styled",
        "shape": "square",
        "errorCorrectionLevel": "M",
        "margin": 0,
        "dots": {
          "type": "extra-rounded",
          "color": "#1A1A1A",
          "gradient": null
        },
        "cornersSquare": {
          "type": "extra-rounded",
          "color": "#1A1A1A",
          "gradient": null
        },
        "cornersDot": {
          "type": "dot",
          "color": "#C0392B",
          "gradient": null
        },
        "background": {
          "color": "#FAFAF7",
          "transparent": false,
          "gradient": null,
          "round": 0
        },
        "image": null,
        "imageOptions": {
          "imageSize": 0.4,
          "margin": 2,
          "mode": "center"
        }
      },
      "created_at": "2026-10-25T10:00:00.000Z"
    }
  ]
}
get/v1/styles/{id}Hent stil

One saved style.

Scope styles:read

Parametre

GET /styles/{id} · Parametre
NavnITypePåkrevdBeskrivelse
idstistring · uuidjaStyle id. A value that is not a UUID → 404.
Eksempel · curl
curl "https://api.qsy.no/v1/styles/9c8b7a6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d" \
  -H "Authorization: Bearer $QSY_API_KEY"
Svar · 200 · application/json
{
  "id": "9c8b7a6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
  "name": "Bistro Nord",
  "qr_config": {
    "mode": "styled",
    "shape": "square",
    "errorCorrectionLevel": "M",
    "margin": 0,
    "dots": {
      "type": "extra-rounded",
      "color": "#1A1A1A",
      "gradient": null
    },
    "cornersSquare": {
      "type": "extra-rounded",
      "color": "#1A1A1A",
      "gradient": null
    },
    "cornersDot": {
      "type": "dot",
      "color": "#C0392B",
      "gradient": null
    },
    "background": {
      "color": "#FAFAF7",
      "transparent": false,
      "gradient": null,
      "round": 0
    },
    "image": null,
    "imageOptions": {
      "imageSize": 0.4,
      "margin": 2,
      "mode": "center"
    }
  },
  "created_at": "2026-10-25T10:00:00.000Z",
  "updated_at": "2026-10-25T10:05:00.000Z"
}
get/v1/styles/{id}/previewForhåndsvis en stil (SVG)

Renders a saved style as an SVG preview for style pickers. The code in the image always encodes the fixed sample URL https://qsy.no; no parameter can change what it encodes. Use id "default" for the house default style. To get the code of a real link, use GET /links/{id}/qr.

Scope styles:read

Parametre

GET /styles/{id}/preview · Parametre
NavnITypePåkrevdBeskrivelse
idstistringjaStyle id (UUID), or "default".
formatspørring"svg"neiOnly svg.
sizespørringintegerneiPixel size of the SVG coordinate system, clamped to 128-1024 (default 512; invalid → 512).
Eksempel · curl
curl "https://api.qsy.no/v1/styles/id/preview" \
  -H "Authorization: Bearer $QSY_API_KEY" \
  -o qr.svg
Svar · 200 · image/svg+xml
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">…</svg>

API-et følger med Bedrift.

Med Bedrift lager du nøkler under Konto og er i gang med en gang. Hva Bedrift ellers rommer, står på prissiden.