Zum Inhalt springen
QRflick

REST-API & Webhooks

Erstelle, ändere und lies deine dynamischen QR-Codes aus deiner eigenen Software und erhalte einen signierten Webhook, wenn etwas gescannt wird oder ein Lead eingeht.

Die REST-API und Webhooks sind derzeit geschlossen. Schlüssel kannst du unter Einstellungen → Entwickler vorbereiten. Die Verfügbarkeit von MCP wird separat gesteuert.

Basis-URL: https://qrflick.com/api/v1

Maschinenlesbare Referenz (OpenAPI 3.1) für Postman, Codegeneratoren und KI-Tools: https://qrflick.com/developers/openapi.json

Sichere Wiederholungen: Sende einen Idempotency-Key-Header bei POST /qr-codes und POST /webhooks. Wiederholst du denselben Schlüssel mit demselben Body innerhalb von 24 Stunden, erhältst du die erste Antwort, statt ein Duplikat zu erstellen. Verwende Schlüssel nicht für verschiedene Anfragen. Multipart-Logo-Uploads und der statische Renderer bieten keine Wiederholungsgarantie.

Du nutzt Claude oder einen anderen KI-Assistenten? Verbinde unseren MCP-Server unter https://qrflick.com/mcp, um Codes in natürlicher Sprache zu erstellen und zu verwalten (unter Einstellungen → Entwickler steht, wie).

Schritt-für-Schritt-Anleitungen: QR-Codes in grossen Mengen mit der API erstellen · QR-Codes über Claude verwalten

Authentifizierung

Jede Anfrage enthält einen API-Schlüssel im Authorization-Header. Schlüssel gehören zu einem Konto (oder Team-Arbeitsbereich) und werden unter Einstellungen → Entwickler vom Inhaber oder einem Admin erstellt.

curl https://qrflick.com/api/v1/me \
  -H "Authorization: Bearer api_…"
  • Schlüssel mit Lesezugriff können Codes, Karten, Leads, Scans und Bilder auflisten und abrufen.
  • Schlüssel mit Lese- und Schreibzugriff können zusätzlich Codes und Webhook-Endpunkte erstellen, ändern und löschen.
  • Ein Schlüssel funktioniert nicht mehr, wenn die Person, die ihn erstellt hat, das Team verlässt oder kein Admin mehr ist, oder wenn das Konto einen Tarif mit API-Zugriff verlässt.

Erstelle einen Schlüssel unter Einstellungen → Entwickler.

Anfragen, Fehler und Limits

Sende und empfange JSON. Datumsangaben sind ISO 8601 in UTC. IDs sind die 12-stelligen IDs, die du in den Dashboard-URLs siehst.

Listen sind paginiert: Verwende ?page= und ?per_page= (bis 100). Antworten enthalten data, links und meta. Jeder Schlüssel hat ein Anfragelimit pro Minute; der Header X-RateLimit-Remaining zeigt, wie viel übrig ist.

StatusBedeutung
401Fehlender, falscher oder widerrufener Schlüssel.
403Der Schlüssel ist schreibgeschützt, der Tarif hat keinen API-Zugriff oder die Aktion ist nicht erlaubt.
404Kein solcher Datensatz in diesem Konto.
422Etwas in der Anfrage ist ungültig oder überschreitet ein Tarif-Limit; errors nennt das Feld.
429Zu viele Anfragen. Warte die Sekunden aus Retry-After ab.
{
  "message": "The name field is required.",
  "errors": { "name": ["The name field is required."] }
}

Endpunkte

AnfrageFunktion
GET /me Konto, Tarif, Schlüssel und Limits. Praktisch, um eine Verbindung zu testen.
GET /design-options Alle Muster, Ecken, Rahmen und Limits, die das design-Objekt akzeptiert, mit Bezeichnungen.
GET /qr-types Aktuelle QR-Typen, verschachtelte Payload-Constraints, Beispiele und ob jeder Typ über die API erstellt werden kann.
GET /folders Ordnernamen und wie viele Codes jeder enthält.
GET /tags Verwendete Tag-Namen.
POST /static-qr-codes Rendert einen statischen Code aus type und Feldern (url, wifi, vcard, whatsapp …) mit beliebigem Design: svg, png oder json. Es wird nichts gespeichert.
POST /uploads/logos Lädt ein Logo hoch (Multipart-Feld file). Verwende die zurückgegebene ID als design.logo_upload_id. (braucht Lesen & Schreiben)
GET /qr-codes Deine dynamischen Codes, neueste zuerst, jeweils mit gespeichertem Design. Filter: search, type, folder, tag, archived.
POST /qr-codes Erstellt einen Code: type, name, payload und optional design. (braucht Lesen & Schreiben)
GET /qr-codes/{id} Ein Code mit Kurzlink, Ziel und Scan-Anzahl.
PATCH /qr-codes/{id} Ändert name, payload, type, design, folder, tags, paused oder archived (true/false). Der gedruckte Code bleibt gleich. (braucht Lesen & Schreiben)
DELETE /qr-codes/{id} Löscht einen Code. Sein Kurzlink zeigt dann „nicht gefunden“. (braucht Lesen & Schreiben)
GET /qr-codes/{id}/image Der Code als png, svg, pdf oder eps: ?format= und ?size= (Pixel) oder ?mm= und ?dpi=.
GET /qr-codes/{id}/scans Scans pro Tag und Aufschlüsselungen (country, city, device, os, browser, language, referrer): ?from= und ?to= (YYYY-MM-DD).
GET /qr-codes/{id}/poll-results Status der Umfrage, Gesamtzahl der Stimmzettel und Stimmen sowie Prozentwert pro Option. Keine Identitäten der Abstimmenden.
GET /qr-codes/{id}/form-responses Paginierte Formularantworten mit Einwilligung und Quell-/UTM-Zuordnung. Filter: since, source, page und per_page.
GET /cards Deine digitalen Visitenkarten.
GET /cards/{id} Eine Karte mit Seite und Kurzlink.
GET /cards/{id}/leads Auf einer Karte geteilte Kontakte, neueste zuerst. ?since= liefert nur neuere.
GET /webhooks Deine Webhook-Endpunkte.
POST /webhooks Abonniert eine URL für Ereignisse (url, events). Die Antwort enthält das Signatur-Secret. (braucht Lesen & Schreiben)
DELETE /webhooks/{id} Kündigt das Abo eines Endpunkts. (braucht Lesen & Schreiben)

POST /static-qr-codes funktioniert auch mit Schlüsseln mit Lesezugriff: Es rendert ein Bild und speichert nichts.

Verbinde deine Anwendung

Schlüssel gehören zum Arbeitsbereich, den du gerade nutzt. Erstelle für jede Integration einen eigenen Schlüssel.

  1. Erstelle unten einen benannten Schlüssel. Wähle „Nur lesen“ für Berichte oder „Lesen & schreiben“, um Codes zu erstellen und zu ändern.
  2. Kopiere den Schlüssel einmalig und speichere ihn in der Umgebung deines Servers oder einem Secret-Manager. Halte ihn aus Browser-Code, Mobile-App-Bundles und öffentlichen Repositories heraus.
  3. Ersetze YOUR_API_KEY im Beispiel und rufe /me auf, um Konto, Zugriff und aktuelle Limits zu prüfen.
curl "https://qrflick.com/api/v1/me" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"

Um einen Schlüssel zu rotieren, erstelle einen Ersatz, aktualisiere deine Integration und prüfe, ob sie funktioniert. Widerrufe dann den alten Schlüssel. Widerrufene Schlüssel funktionieren sofort nicht mehr.

Umfragen, Formulare und gehostete Seiten

Erstelle Umfragen und Formulare über POST /qr-codes und bearbeite sie über PATCH /qr-codes/{id}. Events unterstützen jetzt Veranstalter, Veranstaltungsorte und Programme; Gutscheine unterstützen ein Angebot und Bedingungen. Nutze GET /qr-types für die aktuellen Felder, Validierungsregeln und Beispiele. Regeln verwenden die Constraints required, nullable, min, max und in; Pfade mit Punkten beschreiben verschachtelte Felder und * steht für jedes Array-Element. Die Validierung auf dem Server bleibt massgeblich, einschliesslich Tariflimits und URL-Prüfungen.

Das design auf oberster Ebene steuert das QR-Bild. Das separate payload.design steuert die gehostete Seite: Markenname, Preset, Farben, Schrift, Layout und Button-Stil. Lies das gespeicherte payload vor dem Bearbeiten und behalte die IDs von Feldern und Optionen bei. PATCH ersetzt das komplette payload, wenn es mitgeschickt wird; gib jedes Feld an, das du behalten willst. Ohne payload bleibt es unverändert. Optionen mit Stimmen können nicht entfernt werden.

Umfrage

POST /api/v1/qr-codes
{
    "type": "poll",
    "name": "Umfrage",
    "payload": {
        "title": "Which workshop should we run?",
        "options": [
            {
                "label": "Photography"
            },
            {
                "label": "Design"
            }
        ],
        "choice": "single",
        "vote_limit": "person",
        "results": "after_vote",
        "design": {
            "preset": "sage",
            "layout": "rounded",
            "brand_name": "Studio"
        }
    }
}

Formular

POST /api/v1/qr-codes
{
    "type": "form",
    "name": "Formular",
    "payload": {
        "title": "Request a quote",
        "fields": [
            {
                "type": "email",
                "label": "Your email",
                "required": true
            },
            {
                "type": "textarea",
                "label": "What do you need?"
            }
        ],
        "controller": "Example Studio",
        "privacy_url": "https://example.com/privacy",
        "retention_days": 365,
        "thank_you": "Thank you. We will be in touch.",
        "design": {
            "preset": "ocean",
            "layout": "editorial"
        }
    }
}

Event

POST /api/v1/qr-codes
{
    "type": "event",
    "name": "Event",
    "payload": {
        "title": "Studio open day",
        "starts_at": "2030-06-15T10:00",
        "ends_at": "2030-06-15T17:00",
        "timezone": "Europe/Madrid",
        "organizer": "Example Studio",
        "venue_name": "Main studio",
        "agenda": [
            {
                "time": "10:00",
                "title": "Welcome",
                "speaker": "Studio team"
            }
        ],
        "design": {
            "preset": "sage"
        }
    }
}

Gutschein

POST /api/v1/qr-codes
{
    "type": "coupon",
    "name": "Gutschein",
    "payload": {
        "title": "Welcome offer",
        "code": "WELCOME10",
        "offer": "10% off",
        "terms": "One use per customer.",
        "design": {
            "preset": "clay"
        }
    }
}

GET /qr-codes/{id}/poll-results liefert die Gesamtzahl der Stimmzettel und Stimmen sowie Prozentwerte pro Option; die Prozente beziehen sich auf alle gewählten Optionen. GET /qr-codes/{id}/form-responses liefert Antworten, Einwilligungstext, Land, Platzierungsquelle und UTM-Zuordnung. Antworten kommen neueste zuerst: Nutze page, per_page (1–100), since (exklusiver Zeitstempel) und source (ein Platzierungs-Slug oder - für den Hauptcode). Beide akzeptieren Schlüssel mit Lesezugriff. Behandle Formularantworten als personenbezogene Daten; Wähler-IDs und E-Mail-Abonnentenlisten werden nie zurückgegeben.

Digitale Visitenkarten, Unternehmensprofile und Inhalte digitaler Speisekarten werden weiterhin im Dashboard erstellt und bearbeitet. Deren QR-Codes können aufgelistet und heruntergeladen werden. Formulareinsendungen und Umfragestimmen lösen derzeit keine Webhooks aus: Frage diese Berichts-Endpunkte regelmässig ab. Die API gibt keine Stimmen oder Formularantworten ab.

Referenz zum MCP-Connector

Verbinde einen MCP-Client mit der URL unten und melde dich an, um deinen Arbeitsbereich und Zugriff zu wählen. Alternativ können Clients, die eigene Header unterstützen, einen REST-API-Schlüssel als Authorization: Bearer YOUR_API_KEY senden. OAuth-Tokens des Connectors funktionieren nur auf /mcp; REST-Anfragen brauchen einen API-Schlüssel.

https://qrflick.com/mcp

Nutze get_qr_types, bevor du eine Umfrage, ein Formular oder eine umfangreichere gehostete Seite erstellst. Nutze get_poll_results für Stimmenzahlen und list_form_responses für eingesendete Antworten und Quellfilter. Verbindungen mit Lesezugriff können diese Berichte nutzen. Der Connector bietet kein Lösch-Tool; pausiere oder archiviere Codes stattdessen.

Die Berechtigung „Lesen & schreiben“ ist erforderlich für upload_logo, create_qr_code, create_qr_codes, update_qr_code, set_qr_code_protection und set_qr_code_rules. Die anderen Tools lesen nur oder rendern Bilder.

  • get_qr_types
  • get_poll_results
  • list_form_responses
  • get_account
  • list_qr_codes
  • get_qr_code
  • get_qr_code_scans
  • get_account_scans
  • export_scans_csv
  • get_qr_code_image
  • get_design_options
  • list_folders_and_tags
  • list_logos
  • render_static_qr_code
  • list_cards
  • list_card_leads
  • upload_logo
  • create_qr_code
  • create_qr_codes
  • update_qr_code
  • set_qr_code_protection
  • set_qr_code_rules

Beispiel: Code erstellen und ändern

Erstelle einen Website-Code. Die Antwort enthält den Kurzlink zum Drucken oder Teilen.

curl -X POST https://qrflick.com/api/v1/qr-codes \
  -H "Authorization: Bearer api_…" \
  -H "Content-Type: application/json" \
  -d '{"type": "url", "name": "Summer menu", "payload": {"url": "https://example.com/menu"}}'
{
  "data": {
    "id": "k3v9x2m7qa1b",
    "object": "qr_code",
    "name": "Summer menu",
    "type": "url",
    "payload": { "url": "https://example.com/menu" },
    "short_url": "https://qrflick.com/Ab3xY9k",
    "domain": "qrflick.com",
    "destination": "https://example.com/menu",
    "status": "active",
    "scans": 0,
    "last_scanned_at": null,
    "archived": false,
    "created_at": "2026-01-31T10:00:00+00:00",
    "updated_at": "2026-01-31T10:00:00+00:00"
  }
}

Optional „domain“: der Host einer Plattform-Weiterleitungsdomain, die dein Arbeitsbereich nutzen darf (wie beim Erstellen eines Codes in der App angeboten). Lass es weg für die Standard-Kurzdomain. Die Adresse kann nach dem Erstellen nicht über die API geändert werden.

Später leitest du denselben gedruckten Code woanders hin:

curl -X PATCH https://qrflick.com/api/v1/qr-codes/k3v9x2m7qa1b \
  -H "Authorization: Bearer api_…" \
  -H "Content-Type: application/json" \
  -d '{"payload": {"url": "https://example.com/autumn-menu"}}'

Lade ihn als druckfertiges SVG mit 40 mm Breite herunter:

curl "https://qrflick.com/api/v1/qr-codes/k3v9x2m7qa1b/image?format=svg&mm=40" \
  -H "Authorization: Bearer api_…" -o menu.svg

QR-Code-Typen und Payload-Felder

Der payload enthält die Felder für den Typ des Codes. Codes für Visitenkarten und Profile werden mit ihrer Karte bzw. ihrem Profil erstellt, nicht hier.

typePayload-Felder
url url*
whatsapp phone*, message
phone phone*
email email*, subject, body
sms phone*, message
maps query*
google_review review_url, place_id
link_bio Pro title*, description, links*, theme, avatar_upload_id, design, design.brand_name, design.accent, design.background, design.surface, design.text, design.font, design.layout, design.button_style, design.preset
menu Pro title*, description, menu_url*
app_store Pro ios_url*, android_url*, fallback_url
event Pro title*, description, starts_at*, ends_at, location, url, organizer, venue_name, timezone, details, agenda, agenda.*, agenda.*.time*, agenda.*.title*, agenda.*.speaker, agenda.*.description, design, design.brand_name, design.accent, design.background, design.surface, design.text, design.font, design.layout, design.button_style, design.preset
coupon Pro title*, description, code*, expires_at, url, offer, terms, design, design.brand_name, design.accent, design.background, design.surface, design.text, design.font, design.layout, design.button_style, design.preset
social platform*, handle*
file title*, description, file_url
poll title*, description, options*, options.*, options.*.id, options.*.label*, options.*.image_upload_id, choice, max_choices, vote_limit, results, starts_at, ends_at, timezone, collect_emails, design, design.brand_name, design.accent, design.background, design.surface, design.text, design.font, design.layout, design.button_style, design.preset
form title*, description, fields*, fields.*, fields.*.id, fields.*.type*, fields.*.label*, fields.*.help, fields.*.required, fields.*.options, fields.*.min, fields.*.max, submit_label, thank_you, redirect_url, controller, privacy_url, retention_days, notify, design, design.brand_name, design.accent, design.background, design.surface, design.text, design.font, design.layout, design.button_style, design.preset

* Pflichtfeld. Pro-Typen erfordern einen Tarif mit Smart Redirects.

Webhooks

Füge unter Einstellungen → Entwickler (oder mit POST /webhooks) einen Endpunkt hinzu und wähle seine Ereignisse. Jedes Ereignis wird per POST als JSON gesendet:

EreignisGesendet, wenn
qr_code.createdEin QR-Code wurde erstellt.
qr_code.updatedEin QR-Code hat ein neues Ziel, einen neuen Status oder eine neue Einstellung.
qr_code.deletedEin QR-Code wurde gelöscht.
scan.createdJemand hat einen Code gescannt (Bots und Link-Vorschauen sind ausgenommen).
lead.createdJemand hat seinen Kontakt auf einer Karte geteilt oder über ein Profil geschrieben.
POST /your/endpoint
Content-Type: application/json
webhook-id: evt_01jbx6q9d2m8w4k7r3t5y0a1bc
webhook-timestamp: 1767225600
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=

{
  "id": "evt_01jbx6q9d2m8w4k7r3t5y0a1bc",
  "type": "scan.created",
  "created_at": "2026-01-01T00:00:00+00:00",
  "data": {
    "qr_code": { "id": "k3v9x2m7qa1b", "name": "Summer menu", "type": "url" },
    "short_url": "https://qrflick.com/Ab3xY9k",
    "scanned_at": "2026-01-01T00:00:00+00:00",
    "country": "ES", "city": "Madrid", "device": "mobile", "os": "ios",
    "browser": "safari", "language": "es", "referrer": null, "variant": null
  }
}
  • Antworte innerhalb von 10 Sekunden mit einem beliebigen 2xx-Status; erledige langsame Arbeit nach der Antwort.
  • Alles andere wird nach 1 min, 5 min, 30 min, 2 h, 6 h wiederholt.
  • Schlagen 20 Ereignisse in Folge bei jedem Versuch fehl, wird der Endpunkt pausiert und der Inhaber erhält eine E-Mail.
  • Wiederholungen und „Erneut senden“ behalten dieselbe webhook-id: Nutze sie, um Duplikate zu überspringen.
  • Scans enthalten nie IP-Adressen. Lead-Ereignisse enthalten die Kontaktdaten, die der Besucher teilen wollte.

Signaturen prüfen

Zustellungen werden nach Standard Webhooks signiert. Signiere „webhook-id.webhook-timestamp.raw body“ mit HMAC-SHA256, mit dem base64-dekodierten Teil deines Secrets nach whsec_, und vergleiche mit dem webhook-signature-Header. Lehne alte Zeitstempel ab, um Replays zu verhindern.

// PHP
$secret  = 'whsec_…';
$payload = $id . '.' . $timestamp . '.' . $rawBody;
$key     = base64_decode(substr($secret, 6));
$expected = 'v1,' . base64_encode(hash_hmac('sha256', $payload, $key, true));
$valid = abs(time() - (int) $timestamp) < 300
    && hash_equals($expected, $signatureHeader);
// Node.js
import crypto from 'node:crypto';
const key = Buffer.from(secret.slice(6), 'base64');
const expected = 'v1,' + crypto.createHmac('sha256', key)
  .update(`${id}.${timestamp}.${rawBody}`).digest('base64');
const valid = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300
    && Buffer.byteLength(expected) === Buffer.byteLength(signatureHeader)
    && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));

Standard-Webhooks-Bibliotheken (standardwebhooks.com) für die meisten Sprachen prüfen das für dich.

Deine nächste Verbindung wartet.
Mach deinen nächsten Scan
zum Anfang von etwas.

Dein nächster Kunde sucht vielleicht schon. Mach es leicht, dich zu finden.

Ersten QR-Code kostenlos erstellen Keine Kreditkarte. Kein Ablaufdatum. Nur Möglichkeiten.