Ga naar inhoud

QR-Codes API

Overzicht

De Codes-API is het hart van qr3.app. Hiermee kun je dynamische en statische QR-codes maken, bijwerken en verwijderen.

Basis-URL: https://qr3.app/v1/codes

Bindend REST-contract

Het volgende contract geldt voor alle clients:

  • POST /v1/codes accepteert uitsluitend de typen url, vcard, wifi, email, sms en location. Velden zijn plat: url; ten minste vcard_first_name of vcard_last_name; wifi_ssid; email_to; sms_phone; of beide location_lat en location_lng.
  • Alleen url-codes kunnen dynamisch zijn. Aanmaakverzoeken kunnen optioneel expires_at als ISO 8601-tijdstempel bevatten; ab_enabled, ab_target_url_b en ab_weight_a (A/B-bestemmingen) zijn toegestaan voor dynamische url-codes; redirect_after_expiry maakt geen deel uit van het aanmaakcontract.
  • GET /v1/codes ondersteunt alleen limit, cursor en status (live, paused, flagged, draft).
  • POST /v1/codes/batch accepteert url, vcard en wifi. De limiet is 10 voor Free, 500 voor Pro en 1.000 records voor Business/Agency/Enterprise per verzoek. URL-scans worden synchroon uitgevoerd voor maximaal 50 URL-items; boven 50 is skip_url_scan: true vereist.

QR-code maken

POST /v1/codes

Terminal window
curl -X POST https://qr3.app/v1/codes \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{
"type": "url",
"url": "https://example.com",
"title": "Mein erster QR-Code",
"tags": ["marketing", "q1"],
"is_dynamic": true
}'

Response (HTTP 201):

{
"data": {
"id": "qr_a1b2c3d4",
"short_code": "r7f3Kx",
"redirect_url": "https://qr3.app/r7f3Kx",
"image_svg_url": "https://qr3.app/v1/codes/r7f3Kx/qr.svg",
"image_png_url": "https://qr3.app/v1/codes/r7f3Kx/qr.png",
"image_pdf_url": "https://qr3.app/v1/codes/r7f3Kx/qr.pdf",
"image_eps_url": "https://qr3.app/v1/codes/r7f3Kx/qr.eps",
"type": "url",
"target_url": "https://example.com",
"is_dynamic": true,
"status": "live",
"tags": ["marketing", "q1"],
"total_scans": 0,
"created_at": "2026-03-15T10:00:00.000Z"
},
"meta": { "request_id": "req_xyz123" }
}

QR-code-typen

TypeBeschrijvingVerplichte velden
urlWebsite-URL (dynamisch of statisch)url
vcardVisitekaartje (vCard 3.0)vcard_first_name of vcard_last_name
wifiWifi-configuratiewifi_ssid
emailE-mail (mailto:)email_to
smsSmssms_phone
locationLocatie (geo:)location_lat, location_lng

Batch-creatie

POST /v1/codes/batch

Terminal window
curl -X POST https://qr3.app/v1/codes/batch \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "type": "url", "url": "https://produkt-1.example.com", "tags": ["batch"] },
{ "type": "url", "url": "https://produkt-2.example.com", "tags": ["batch"] },
{ "type": "wifi", "wifi_ssid": "GastWLAN", "wifi_password": "geheim123" }
],
"skip_url_scan": false
}'

Response (HTTP 201):

{
"data": {
"created": [
{ "id": "qr_...", "short_code": "abc123", "redirect_url": "https://qr3.app/abc123" },
{ "id": "qr_...", "short_code": "def456", "redirect_url": "https://qr3.app/def456" },
{ "id": "qr_...", "short_code": "ghi789", "status": "live" }
],
"total": 3,
"failed": 0
}
}

QR-codelijst

GET /v1/codes

Terminal window
curl https://qr3.app/v1/codes?status=live&limit=20 \
-H "Authorization: Bearer qr3_sk_..."

Query-parameters:

ParameterTypeStandaardBeschrijving
cursorstring—Cursor voor paginering
limitinteger20Resultaten per pagina (max. 100)
statusstring—Filter: live, paused, flagged, draft

QR-code ophalen

GET /v1/codes/:id

Terminal window
curl https://qr3.app/v1/codes/qr_a1b2c3d4 \
-H "Authorization: Bearer qr3_sk_..."

QR-code bijwerken

PATCH /v1/codes/:id

Update contract: url may be changed only for an existing type: "url" code, and its value must use http:// or https://. Other code types must not receive url; invalid requests return 422.

Dynamische QR-codes maken het mogelijk om de bestemmings-URL op elk moment te wijzigen — zonder dat de QR-code opnieuw gedrukt hoeft te worden.

Terminal window
curl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4 \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{ "url": "https://neue-zielseite.example.com", "status": "live" }'

Voor dynamische url-codes kun je is_landing_page: true instellen (bij het maken of via PATCH). Een scan toont dan een door qr3 gehoste pagina met de openbare bestanden en externe links van de code, in plaats van door te sturen. Externe links worden doorgegeven als een links-array:

{
"is_landing_page": true,
"links": [
{ "label": "Datenblatt", "url": "https://example.com/datenblatt.pdf" },
{ "label": "Zertifikat", "url": "https://example.com/zertifikat.pdf" }
]
}
  • 0–20 links per code; label is 1–100 tekens; url moet http(s) zijn (≤ 2048 tekens).
  • Elke URL wordt gecontroleerd met Google Web Risk — een onveilige URL retourneert 422.
  • Als Web Risk bij het opslaan niet bereikbaar is, wordt de link toch geaccepteerd, maar gemarkeerd voor een nieuwe controle. Een dagelijkse taak controleert opgeslagen links opnieuw (en controleert als veilig geclassificeerde links regelmatig opnieuw) en pauzeert de code automatisch als een link later als onveilig wordt herkend.
  • "links": [] verwijdert alle links. Zie de handleiding voor bestemmingspagina’s.

QR-code verwijderen

DELETE /v1/codes/:id

Soft-delete — de QR-code wordt gearchiveerd, scangegevens blijven behouden.

Een tweede DELETE op dezelfde code retourneert 404, zelfs als beide aanvragen tegelijkertijd aankomen. De qr.deleted webhook wordt precies één keer verzonden.

Terminal window
curl -X DELETE https://qr3.app/v1/codes/qr_a1b2c3d4 \
-H "Authorization: Bearer qr3_sk_..."

QR-afbeeldingen downloaden

Alle afbeeldingsformaten zijn openbaar toegankelijk — geen authenticatie vereist.

FormaatURLGebruik
SVG (vector)/v1/codes/:code/qr.svgWeb, schalen, digitaal
PNG (raster)/v1/codes/:code/qr.pngE-mail, presentaties
PDF (vector)/v1/codes/:code/qr.pdfStandaard: vierkant (alleen de code); ?format=a4 voor een printvel
EPS (vector)/v1/codes/:code/qr.epsProfessionele drukwerk-workflows (Adobe, drukkerijen)

Optioneel: ?size=N — modulegrootte in pixels (2–20, standaard: 4) voor SVG, PNG en EPS. De PDF gebruikt een vaste modulegrootte.

Alleen PDF: ?format=a4|square — paginaformaat (standaard: square — alleen code + quiet zone, geen A4-witruimte; a4 voor een printklaar A4-vel)

Terminal window
# SVG für Web
curl https://qr3.app/v1/codes/r7f3Kx/qr.svg
# PNG in hoher Auflösung
curl https://qr3.app/v1/codes/r7f3Kx/qr.png?size=10 -o qr-hires.png
# Kompaktes PDF (nur der Code, Standard)
curl https://qr3.app/v1/codes/r7f3Kx/qr.pdf -o qr.pdf
# Druckfertiges A4-Blatt
curl "https://qr3.app/v1/codes/r7f3Kx/qr.pdf?format=a4" -o qr-a4.pdf

Kleuren en foutcorrectie

Alle vier de afbeeldingsroutes accepteren drie optionele parameters. Ze gelden voor deze specifieke opvraging en hebben voorrang op kleuren die bij de code zijn opgeslagen (volgende sectie).

ParameterWaardenStandaardSVG, PNGPDF, EPS
fgHex RRGGBB of RGB000000wordt getekendwordt getekend als drukkleur
bgHex zoals fg of transparentffffffwordt getekendwordt getekend als drukkleur
eccL, M, Q, HMheeft effectheeft effect
  • Schrijfwijze: Hoofdlettergevoeligheid maakt niet uit, de # is optioneel. Bij het verzenden wordt deze gecodeerd als %23.
  • Ongeldige waarden tellen als niet ingesteld. ?fg=lila levert de op de code opgeslagen kleur, of het normale zwart als er geen is opgeslagen, met 200 en nooit een fout. Alleen een expliciete ?fg=000000 dwingt zwart af.
  • bg=transparent levert een SVG, PDF of EPS zonder achtergrond en een PNG met een echt alfakanaal. De ondergrond waarop de code wordt geplaatst, moet licht zijn en rondom 4 modules stille zone vrijlaten. Een donkere code op een donkere ondergrond is niet leesbaar.
  • PDF en EPS schrijven zwart en grijs als grijswaarden (alleen zwartplaat) en elke andere kleur als CMYK in hele procenten, bijvoorbeeld 1F4E79 als C74 M36 Y0 K53. Zodra er een kleur is gekozen, ligt er achter de code en de stille zone een dekkend vlak, wit of in de kleur van bg, net als bij de SVG. Zonder kleuren blijven beide bestanden ongewijzigd. Omrekening en beperkingen: Drukkleuren.
  • Leesbaarheid: De afbeeldingsroute controleert het contrast niet. Aanbevolen is minimaal 4:1 en donkere modules op een lichte achtergrond. #1F4E79 op wit heeft 8,7:1, #ff6600 op wit slechts 2,9:1.
  • ecc wijzigt het puntenpatroon, niet de inhoud. Een gedrukte code blijft werken, maar oude en nieuwe drukbestanden mogen niet worden gemengd. Q of H maken de code robuuster, bijvoorbeeld op golfkarton. Een logo vereist altijd H.
  • Met logo blijft het vlak achter het logo wit, ook bij een gekleurde of transparante achtergrond.
  • Caching: Alleen de feitelijke standaardafbeelding (zwart op wit, foutcorrectie M, geen logo) wordt gedurende 24 uur als onveranderlijk geleverd; elke andere weergave gedurende 5 minuten. Voor PDF en EPS geldt elke opgegeven achtergrond als een afwijking: bg=ffffff tekent daar een wit vlak dat het standaardbestand niet heeft.
  • Tarief: Kleuren en foutcorrectie zijn beschikbaar in elk tarief, ook in het gratis tarief.
Terminal window
# Dark blue code on white
curl "https://qr3.app/v1/codes/r7f3Kx/qr.svg?fg=1F4E79" -o qr-blue.svg
# Transparent PNG for a layout on a light surface
curl "https://qr3.app/v1/codes/r7f3Kx/qr.png?size=10&bg=transparent" -o qr-transparent.png
# More robust for corrugated board: error correction Q
curl "https://qr3.app/v1/codes/r7f3Kx/qr.pdf?ecc=Q" -o qr-q.pdf

Kleuren bij de code opslaan

PATCH /v1/codes/:id slaat kleuren op als appearance bij de code. De afbeeldingsroutes tekenen deze dan standaard, zonder parameters.

Terminal window
curl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4 \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{"appearance": {"foreground_color": "#1F4E79"}}'

Antwoord (HTTP 200, ingekort):

{
"data": {
"id": "qr_a1b2c3d4",
"short_code": "r7f3Kx",
"appearance": { "foreground_color": "#1F4E79", "background_color": null }
},
"meta": { "request_id": "req_xyz", "issues": [] }
}
  • Waarden: foreground_color als #RRGGBB, background_color als #RRGGBB of transparent. Andere sleutels resulteren in 400.
  • Samenvoegen: Een weggelaten veld behoudt zijn opgeslagen waarde. null reset een veld, "appearance": null beide. Zwart en wit worden niet opgeslagen; het antwoord toont ze als null.
  • Elk code-antwoord bevat appearance, evenals de webhooks qr.created en qr.updated.
  • Volgorde in de afbeeldingsroutes: eerst de parameter, dan de opgeslagen kleur, dan de standaard. ?fg=000000 levert daarom het zwarte drukbestand van een gekleurde code op.
  • Ingebedde afbeeldingen: Een afbeeldings-URL volgt de opgeslagen kleuren voor zover deze die niet zelf met fg en bg vastlegt: een URL zonder parameters voor beide kleuren, ?fg=000000 voor de achtergrond, ?ecc=Q eveneens voor beide. Na een kleurwijziging kan een pagina die een dergelijke URL insluit nog de oude afbeelding tonen: tot 24 uur als de URL tot dan toe de standaardafbeelding leverde (zwart op wit, foutcorrectie M, zonder logo), anders tot 5 minuten. De oplossing is een eigen parameter aan de URL die bij elke kleurwijziging verandert, zoals ?v=2 of de updated_at van de code zoals in het dashboard. De afbeeldingsroutes negeren onbekende parameters.
  • Foutcorrectie wordt nooit opgeslagen. Deze wordt per download gekozen met ?ecc=.
  • Alleen via PATCH: POST /v1/codes, de batch en de import weigeren appearance met 422.
  • PDF en EPS tekenen opgeslagen kleuren als drukkleuren, net als de parameters. Omdat wit nooit wordt opgeslagen, krijgt een code met een opgeslagen voorgrondkleur daar een wit vlak, net als in de SVG.

Contrastcontrole

De API controleert het paar dat voortvloeit uit de aanvraag en de opgeslagen waarde:

NiveauWanneerAntwoord
blockedcontrast onder 1,5:1422, er wordt niets opgeslagen
criticalonder 2:1 of helderheidsverschil onder 0,30; een waarschuwing samen met een logo; elke transparante achtergrond200 met meta.issues
warningonder 4:1 of helderheidsverschil onder 0,50; lichte modules op een donkere achtergrond200 met meta.issues
okal het andere200, meta.issues is leeg

Elk item in meta.issues heeft code, severity, field, message en optioneel hints zoals contrast_ratio — dezelfde vorm als de compliance-meldingen van een digitaal productpaspoort. Een transparante achtergrond wordt nooit geblokkeerd, omdat een lichte code op een donkere verpakking een echte use-case is. De ondergrond heeft desondanks een duidelijk contrast nodig en rondom een vrije rustzone van 4 modules.

Het uploaden en verwijderen van een logo (POST en DELETE /v1/codes/:id/logo) voeren dezelfde controle uit op de opgeslagen kleuren en retourneren de bevindingen eveneens in meta.issues: met een logo wordt een waarschuwing critical, zonder logo is het weer een waarschuwing.

Als een andere aanvraag dezelfde code op hetzelfde moment wijzigt, past de API de wijzigingen toe op de nieuwste status. Pas als dit drie keer achter elkaar mislukt, antwoordt deze met 409; de client laadt de code dan opnieuw en herhaalt de wijziging.


Multipart-request, veld file: PNG, JPEG of WebP, maximaal 1 MB, herkend aan de Magic Bytes. Normaliseert de afbeelding naar een transparante 512×512-PNG en vervangt een bestaand logo.

Terminal window
curl -X POST https://qr3.app/v1/codes/qr_a1b2c3d4/logo \
-H "Authorization: Bearer qr3_sk_..." \

Antwoord (HTTP 201): de bijgewerkte code, met ingestelde logo_file_id.

Verwijdert het logo en wist het opgeslagen object. Idempotent — een aanroep zonder bestaand logo retourneert nog steeds 200.

Als een andere aanvraag tegelijkertijd het logo van dezelfde code wijzigt (een tweede upload of een verwijdering), antwoorden POST en DELETE /v1/codes/:id/logo met 409 (errors/conflict) en wijzigen ze niets; een geüpload logo wordt weggegooid. Laad de code opnieuw en probeer het nogmaals. Twee gelijktijdige aanroepen van DELETE /v1/codes/:id/logo zijn geen conflict; beide retourneren 200.

Indien ingesteld, sluiten alle vier de formaten — qr.svg, qr.png, qr.pdf en qr.eps — de logo-pixels in en verhogen ze de foutcorrectie naar H. Het volledige contract — inclusief welke wijziging (toevoegen/verwijderen vs. vervangen) het stippenpatroon verandert — evenals printinstructies zijn te vinden onder Logo in de QR-code.


Reacties

Reacties maken feedbackcycli tussen bureaus en klanten mogelijk.

GET /v1/codes/:id/comments

POST /v1/codes/:id/comments

PATCH /v1/codes/:id/comments/:commentId

DELETE /v1/codes/:id/comments/:commentId

Dashboard-reacties worden toegewezen aan de gebruiker die ze heeft aangemaakt (author_id); reacties via pure API-keys blijven niet-toegewezen (author_id: null). Alleen de auteur zelf of een org_admin/ws_admin mag een reactie verwijderen — pure API-keys kunnen alleen niet-toegewezen API-reacties verwijderen.

Terminal window
# Kommentar hinzufügen
curl -X POST https://qr3.app/v1/codes/qr_a1b2c3d4/comments \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{ "body": "QR-Code bitte auf grünen Hintergrund abstimmen.", "author_name": "Max Müller" }'
# Offene Kommentare auflisten
curl "https://qr3.app/v1/codes/qr_a1b2c3d4/comments?resolved=false" \
-H "Authorization: Bearer qr3_sk_..."
# Kommentar als erledigt markieren
curl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4/comments/cmt_xyz \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{ "resolved": true }'