ScanMosaic
REST API · v1

Binde QR-Codes und Kurzlinks in deine App ein

Erstelle dynamische QR-Codes, Kurzlinks und Barcodes, ändere ihre Ziele, lies ihre Scan-Statistiken und rendere druckfertige QR-Bilder, alles aus deinem eigenen Code. JSON über HTTPS, ein API-Schlüssel, verständliche Fehlermeldungen.

Basis-URL
https://scanmosaic.com/api/v1
Auth
Authorization: Bearer tsk_…
Tarif
Business

Schnellstart

  1. Öffne in deinem Dashboard API-Schlüssel (Business-Plan) und erstelle einen Schlüssel. Kopiere ihn: Er wird nur einmal angezeigt.
  2. Speichere ihn als Umgebungsvariable auf deinem Server, z. B. TESSERA_API_KEY. Gib ihn niemals in Browser- oder App-Code ein.
  3. Erstelle einen dynamischen QR-Code. Die Antwort enthält seinen Kurzlink in url; codiere diesen Link oder lade ein fertiges Bild über /qr herunter.

cURL

curl "https://scanmosaic.com/api/v1/items" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind": "qr", "name": "Table menu", "dest": "https://example.com/menu"}'

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "kind": "qr",
    "name": "Table menu",
    "dest": "https://example.com/menu"
  })
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.post(
    "https://scanmosaic.com/api/v1/items",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
    json={
    "kind": "qr",
    "name": "Table menu",
    "dest": "https://example.com/menu"
},
)
r.raise_for_status()
print(r.json()["data"])

cURL

curl "https://scanmosaic.com/api/v1/qr?item=k3Xp9Qa&size=1024" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -o menu.png

JavaScript

import { writeFile } from "node:fs/promises";

const res = await fetch("https://scanmosaic.com/api/v1/qr?item=k3Xp9Qa&size=1024", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile("menu.png", Buffer.from(await res.arrayBuffer()));

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/qr?item=k3Xp9Qa&size=1024",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
open("menu.png", "wb").write(r.content)

Authentifizierung

Sende deinen Schlüssel im Authorization-Header jeder Anfrage. Schlüssel beginnen mit tsk_ und gehören zu einem Workspace: Sie können alles lesen und ändern, was ein Editor dieses Workspace kann, und nichts in anderen Workspaces.

Authorization: Bearer tsk_AbC123…
  • Inhaber und Admins erstellen und löschen Schlüssel im Dashboard unter API-Schlüssel. Ein gelöschter Schlüssel funktioniert sofort nicht mehr.
  • Die API gehört zum Business-Tarif. Wenn der Tarif endet, erhalten Anfragen 402 business_required, bis du verlängerst; deine Codes und Daten bleiben erhalten.
  • Änderungen mit einem Schlüssel erscheinen im Aktivitätsprotokoll des Workspace als „API key tsk_…“.
  • CORS ist offen, sodass du die API von jedem Ursprung aus aufrufen kannst. Ein Schlüssel in einer Webseite kann aber von jedem kopiert werden, der sie öffnet. Rufe die API von deinem Server aus auf.

Fehler

Jeder Fehler hat dieselbe JSON-Form und einen passenden HTTP-Status. code ist stabil: Bau darauf auf. message ist einfaches Englisch für Logs und Menschen. Manche Fehler liefern Details wie param.

{
  "error": {
    "code": "bad_param",
    "message": "One of the parameters isn't valid.",
    "status": 400,
    "param": "size",
    "hint": "64 to 2048"
  }
}
Fehlercodes
StatusCodeBedeutung
400bad_jsonDer Body ist kein gültiges JSON.
400bad_paramEin Query- oder Body-Parameter liegt außerhalb des gültigen Bereichs. details: param, hint.
400bad_destinationdest ist keine vollständige http(s)-Webadresse.
400bad_kindkind ist weder qr, link noch barcode.
400bad_aliasalias besteht nicht aus 3–40 Buchstaben, Ziffern oder Bindestrichen oder ist reserviert.
400domain_not_verifieddomain ist keine verifizierte Domain deines Workspaces.
400unsafe_destinationGoogle Web Risk stuft das Ziel als riskant ein.
400empty / too_long / bad_formatQR-Bilder: keine Daten, zu viele Daten oder ein anderes Format als png oder svg.
400bad_cursorDieser Cursor stammt nicht von uns.
401api_key_requiredKein Authorization-Header, oder er ist nicht Bearer tsk_…
401invalid_api_keyDer Schlüssel existiert nicht oder wurde gelöscht.
402business_requiredDer Workspace hat keinen Business-Tarif (zum Beispiel, weil er beendet wurde).
403limit_reachedDas Limit deines Plans für diese Art von Element ist erreicht. details: limit, kind.
404not_foundDieses Element gibt es in diesem Workspace nicht.
409alias_takenDieser Alias wird auf dieser Domain bereits verwendet.
413too_bigDer Body ist zu groß (250 KB für Items).
429rate_limited / daily_limitZu viele Anfragen. Warte die unter Retry-After angegebenen Sekunden.
500server_errorBei uns ist etwas schiefgelaufen. Versuche es mit zunehmenden Wartezeiten erneut.

Ratenlimits

Jeder Schlüssel kann 120 Anfragen pro Minute und 20,000 pro Tag senden. Jede Antwort zeigt dir, wo du stehst:

KopfbereichBedeutung
X-RateLimit-LimitErlaubte Anfragen pro Minute.
X-RateLimit-RemainingVerbleibende Anfragen in der aktuellen Minute.
X-RateLimit-ResetUnix-Zeit, zu der die Minute zurückgesetzt wird.
Retry-AfterNur bei 429: Sekunden, die du vor dem nächsten Versuch warten sollst.

Das Erstellen von Elementen ist außerdem auf 300 pro Stunde und Workspace begrenzt, und dein Tarif legt fest, wie viele Elemente du behalten kannst. Brauchst du mehr? Schreib uns.

Seitennavigation

Listen liefern die neuesten zuerst, bis zu limit Elemente (Standard 25, höchstens 100). Wenn has_more true ist, übergib next_cursor als cursor, um die nächste Seite zu erhalten. Cursor bleiben gültig, wenn Elemente hinzukommen.

{
  "data": [
    "\u2026"
  ],
  "has_more": true,
  "next_cursor": "MTc2NzIyNTYwMC5rM1hwOVFh"
}

Das Item-Objekt

QR-Codes, Links und Barcodes sind alle Items. Einzelne Items kommen als data zurück, Listen als data mit Paging-Feldern.

Elementfelder
NameTypBeschreibung
idstringKurze ID, zugleich die Standard-Endung des Kurzlinks.
kindqr | link | barcodeWas es ist. Lässt sich nach dem Erstellen nicht mehr ändern.
typestringInhaltstyp, z. B. url (Standard), pdf, menu, vcard für QR-Codes; ean13, code128 für Barcodes.
namestringDeine Bezeichnung, bis zu 80 Zeichen.
deststring | nullWohin Scans und Klicks führen. null bei gehosteten Seiten und Barcodes.
urlstringDer Kurzlink, den der QR-Code kodiert, z. B. https://go.yourbrand.com/menu.
aliasstring | nullEigene Endung (3–40 Buchstaben, Zahlen oder Bindestriche), pro Domain einmalig.
domainstring | nullDeine verifizierte eigene Domain oder null für unsere.
campaignstring | nullElemente für Berichte gruppieren.
contentobject | nullDaten der gehosteten Seite oder Barcode-Daten ({ "data": "…" }).
styleobjectDesign des QR-Codes (Farben, Punkt- und Eckenstile).
rulesobject | nullRouting-Regeln (nach Gerät, Land, Zeit …).
pausedbooleanPausierte Elemente zeigen eine „pausiert“-Seite statt weiterzuleiten.
disabledbooleanVon uns wegen Verstoßes gegen die Bedingungen deaktiviert.
hitsintegerScans insgesamt (QR-Codes) oder Klicks (Links).
last_hitinteger | nullUnix-Zeit des letzten Scans oder Klicks.
created / updatedintegerUnix-Zeiten.

Endpunkte

GET /api/v1/me

Konto

Der Workspace, zu dem dieser Schlüssel gehört, sein Tarif, Limits, Nutzung, verifizierte Domains und Ratenlimits. Praktisch, um zu prüfen, ob ein Schlüssel funktioniert.

cURL

curl "https://scanmosaic.com/api/v1/me" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/me", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/me",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Antwort 200 OK
{
  "data": {
    "workspace": {
      "id": "w_8fK2mQ",
      "name": "Acme"
    },
    "plan": "business",
    "key": {
      "prefix": "tsk_AbC123",
      "name": "Shopify sync"
    },
    "limits": {
      "qr": 1000,
      "link": 5000,
      "barcode": 10000,
      "domains": 5
    },
    "usage": {
      "dynamic": 12,
      "links": 40,
      "barcodes": 3,
      "storageBytes": 0,
      "workspaces": 1
    },
    "domains": [
      "go.yourbrand.com"
    ],
    "rate_limits": {
      "per_minute": 120,
      "per_day": 20000
    }
  }
}

GET /api/v1/items

Elemente auflisten

Elemente im Workspace, neueste zuerst.

Parameter
NameTypBeschreibung
kindqr | link | barcodeNur diese Art.
typestringNur dieser Inhaltstyp, z. B. url oder pdf.
campaignstringNur diese Kampagne.
domainstringNur Elemente auf dieser eigenen Domain.
pausedtrue | falseNur pausierte oder nur aktive Elemente.
qstringSuche nach Name, Ziel und Alias.
limitinteger1–100, Standard 25.
cursorstringnext_cursor von der vorherigen Seite.

cURL

curl "https://scanmosaic.com/api/v1/items?kind=link&campaign=spring&limit=50" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items?kind=link&campaign=spring&limit=50", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/items?kind=link&campaign=spring&limit=50",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Antwort 200 OK
{
  "data": [
    {
      "id": "k3Xp9Qa",
      "kind": "link",
      "type": "url",
      "name": "Spring menu",
      "dest": "https://example.com/menu",
      "content": null,
      "style": {},
      "rules": null,
      "alias": "menu",
      "domain": "go.yourbrand.com",
      "campaign": "spring",
      "og": null,
      "created": 1767225600,
      "updated": 1767225600,
      "paused": false,
      "disabled": false,
      "hits": 42,
      "last_hit": 1767312000,
      "url": "https://go.yourbrand.com/menu"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

POST /api/v1/items

Element erstellen

Erstellt einen dynamischen QR-Code, Kurzlink oder gespeicherten Barcode. Zählt zu den Limits deines Plans.

Parameter
NameTypBeschreibung
kindqr | link | barcodeStandard qr.
dest erforderlichstringVollständige http(s)-Adresse für die Weiterleitung. Wird für Barcodes und gehostete Seiten nicht verwendet.
namestringBis zu 80 Zeichen.
typestringStandard url (Codes, Links) oder code128 (Barcodes).
aliasstringEigene Endung, z. B. menu. 3–40 Buchstaben, Zahlen oder Bindestriche, pro Domain einmalig.
domainstringEine deiner verifizierten eigenen Domains (siehe /domains).
campaignstringBis zu 60 Zeichen.
styleobjectQR-Design, z. B. {"fg": "#112233", "dot": "rounded"}.
contentobjectDaten der gehosteten Seite oder Barcode-Daten, z. B. {"bcid": "ean13", "text": "4006381333931"} für einen Barcode.
rulesobjectRouting-Regeln.
pausedbooleanPausiert starten.

cURL

curl "https://scanmosaic.com/api/v1/items" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind": "link", "name": "Spring menu", "dest": "https://example.com/menu", "alias": "menu", "domain": "go.yourbrand.com", "campaign": "spring"}'

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "kind": "link",
    "name": "Spring menu",
    "dest": "https://example.com/menu",
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring"
  })
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.post(
    "https://scanmosaic.com/api/v1/items",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
    json={
    "kind": "link",
    "name": "Spring menu",
    "dest": "https://example.com/menu",
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring"
},
)
r.raise_for_status()
print(r.json()["data"])
Antwort 201 Created
{
  "data": {
    "id": "k3Xp9Qa",
    "kind": "link",
    "type": "url",
    "name": "Spring menu",
    "dest": "https://example.com/menu",
    "content": null,
    "style": {},
    "rules": null,
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring",
    "og": null,
    "created": 1767225600,
    "updated": 1767225600,
    "paused": false,
    "disabled": false,
    "hits": 42,
    "last_hit": 1767312000,
    "url": "https://go.yourbrand.com/menu"
  }
}

GET /api/v1/items/{id}

Artikel holen

Ein Element per ID.

cURL

curl "https://scanmosaic.com/api/v1/items/k3Xp9Qa" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items/k3Xp9Qa", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/items/k3Xp9Qa",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Antwort 200 OK
{
  "data": {
    "id": "k3Xp9Qa",
    "kind": "link",
    "type": "url",
    "name": "Spring menu",
    "dest": "https://example.com/menu",
    "content": null,
    "style": {},
    "rules": null,
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring",
    "og": null,
    "created": 1767225600,
    "updated": 1767225600,
    "paused": false,
    "disabled": false,
    "hits": 42,
    "last_hit": 1767312000,
    "url": "https://go.yourbrand.com/menu"
  }
}

PATCH /api/v1/items/{id}

Eintrag aktualisieren

Sende nur die Felder, die sich ändern sollen. Eine Änderung von dest gilt ab dem nächsten Scan; gedruckte Codes funktionieren weiter. Eine Änderung von domain oder alias ändert den Kurzlink, sodass bereits gedruckte Codes nicht mehr funktionieren.

Parameter
NameTypBeschreibung
name, dest, alias, domain, campaign, style, content, rules, pausedWie bei „Erstellen“. kind lässt sich nicht ändern. Sende null, um alias, domain, campaign oder rules zu leeren.

cURL

curl -X PATCH "https://scanmosaic.com/api/v1/items/k3Xp9Qa" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dest": "https://example.com/summer-menu", "paused": false}'

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items/k3Xp9Qa", {
  method: "PATCH",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "dest": "https://example.com/summer-menu",
    "paused": false
  })
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.patch(
    "https://scanmosaic.com/api/v1/items/k3Xp9Qa",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
    json={
    "dest": "https://example.com/summer-menu",
    "paused": False
},
)
r.raise_for_status()
print(r.json()["data"])
Antwort 200 OK
{
  "data": {
    "id": "k3Xp9Qa",
    "kind": "link",
    "type": "url",
    "name": "Spring menu",
    "dest": "https://example.com/summer-menu",
    "content": null,
    "style": {},
    "rules": null,
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring",
    "og": null,
    "created": 1767225600,
    "updated": 1767225600,
    "paused": false,
    "disabled": false,
    "hits": 42,
    "last_hit": 1767312000,
    "url": "https://go.yourbrand.com/menu"
  }
}

DELETE /api/v1/items/{id}

Element löschen

Löscht das Element und seinen Scan-Verlauf. Sein Kurzlink funktioniert sofort nicht mehr. Das lässt sich nicht rückgängig machen.

cURL

curl -X DELETE "https://scanmosaic.com/api/v1/items/k3Xp9Qa" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items/k3Xp9Qa", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.delete(
    "https://scanmosaic.com/api/v1/items/k3Xp9Qa",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Antwort 200 OK
{
  "data": {
    "id": "k3Xp9Qa",
    "deleted": true
  }
}

GET /api/v1/items/{id}/stats

Element-Statistiken

Scans oder Klicks über einen Zeitraum: eine Tagesreihe und Aufschlüsselungen nach Land, Gerät, Betriebssystem, Browser, Sprache und Routing-Regel. Bots werden nicht gezählt.

Parameter
NameTypBeschreibung
daysinteger1–365, Standard 30.

cURL

curl "https://scanmosaic.com/api/v1/items/k3Xp9Qa/stats?days=7" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items/k3Xp9Qa/stats?days=7", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/items/k3Xp9Qa/stats?days=7",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Antwort 200 OK
{
  "data": {
    "days": 7,
    "total": 42,
    "last_hit": 1767312000,
    "inRange": 12,
    "series": [
      [
        "2026-01-01",
        3
      ],
      [
        "2026-01-02",
        0
      ],
      [
        "…",
        0
      ]
    ],
    "countries": [
      {
        "k": "GB",
        "n": 7
      },
      {
        "k": "US",
        "n": 5
      }
    ],
    "devices": [
      {
        "k": "Mobile",
        "n": 10
      },
      {
        "k": "Desktop",
        "n": 2
      }
    ],
    "os": [
      {
        "k": "iOS",
        "n": 6
      }
    ],
    "browsers": [
      {
        "k": "Safari",
        "n": 6
      }
    ],
    "langs": [
      {
        "k": "en-gb",
        "n": 7
      }
    ],
    "rules": [
      {
        "k": "default",
        "n": 12
      }
    ]
  }
}

GET /api/v1/qr

QR-Code-Bild

Rendert einen QR-Code als PNG oder SVG. Nutze GET mit Query-Parametern oder sende dieselben Parameter per POST als JSON. Übergib item, um einen gespeicherten Code mit eigenem Design und Kurzlink zu zeichnen, oder data für beliebigen Text.

Parameter
NameTypBeschreibung
datastringText oder Link zum Kodieren (bis zu 2.953 Bytes). Erforderlich, sofern item nicht gesetzt ist.
itemstringID eines gespeicherten QR-Codes oder Links: kodiert seinen Kurzlink mit dem gespeicherten Design.
formatpng | svgStandard png.
sizeintegerPixel, 64–2048 für PNG (Standard 512), 64–4096 für SVG (Standard 1024).
color#RRGGBBPunkte. Standard #141A2E.
background#RRGGBBStandard #FFFFFF.
transparentbooleanTransparenter Hintergrund.
corner_color#RRGGBBEckquadrate. Standard: color.
gradient_color#RRGGBBNur SVG: zweite Farbe eines diagonalen Verlaufs.
error_correctionL | M | Q | HWie viel Beschädigung der Code übersteht: 7 %, 15 %, 25 %, 30 %. Standard M (PNG) oder Q (SVG).
marginintegerRuhezone in Modulen, 0–8. Standard 4.
dot_stylestringsquare, dots, rounded, extra-rounded, classy, classy-rounded
corner_stylestringsquare, extra-rounded, dot
corner_dot_stylestringsquare, dot
downloadstringDateiname: fügt Content-Disposition: attachment hinzu.

PNGs werden auf unseren Servern mit ganzen Pixeln pro Modul gezeichnet, sodass die Kanten für den Druck scharf bleiben. Verläufe und Logos gibt es nur als SVG; für Logos nutze den Generator.

cURL

curl "https://scanmosaic.com/api/v1/qr" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"data": "https://example.com", "format": "png", "size": 1024, "color": "#4865F0", "dot_style": "rounded", "corner_style": "extra-rounded"}' \
  -o qr.png

JavaScript

import { writeFile } from "node:fs/promises";

const res = await fetch("https://scanmosaic.com/api/v1/qr", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "data": "https://example.com",
    "format": "png",
    "size": 1024,
    "color": "#4865F0",
    "dot_style": "rounded",
    "corner_style": "extra-rounded"
  })
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile("qr.png", Buffer.from(await res.arrayBuffer()));

Python

import os, requests

r = requests.post(
    "https://scanmosaic.com/api/v1/qr",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
    json={
    "data": "https://example.com",
    "format": "png",
    "size": 1024,
    "color": "#4865F0",
    "dot_style": "rounded",
    "corner_style": "extra-rounded"
},
)
r.raise_for_status()
open("qr.png", "wb").write(r.content)

GET /api/v1/domains

Domains

Die eigenen Domains des Workspace. Verwende beim Erstellen von Items einen Host, bei dem ready true ist, als domain.

cURL

curl "https://scanmosaic.com/api/v1/domains" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/domains", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/domains",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Antwort 200 OK
{
  "data": [
    {
      "host": "go.yourbrand.com",
      "verified": true,
      "ready": true
    }
  ]
}

Eigene Domains

Mit dem Business-Plan können deine Kurzlinks deine eigene Domain nutzen, z. B. go.yourbrand.com/menu. Füge die Domain im Dashboard unter Domains hinzu und verifiziere sie: Du legst einen CNAME-Eintrag an, der auf uns zeigt, und einen TXT-Eintrag, der beweist, dass die Domain dir gehört, und wir stellen das SSL-Zertifikat aus. Übergib dann domain, wenn du ein Element erstellst oder aktualisierst.

Jede Domain kann ihre nackte Adresse (go.yourbrand.com) und unbekannte Pfade auf Seiten deiner Wahl weiterleiten.

OpenAPI

Die vollständige API ist in openapi.json (OpenAPI 3.1) beschrieben. Importiere sie in Postman, Insomnia oder einen Client-Generator.

Versionierung

v1 ist stabil. Wir können Endpunkte, Felder und Fehlercodes hinzufügen, ignoriere also Felder, die du nicht kennst. In v1 entfernen oder benennen wir nichts um; Breaking Changes kämen als v2 und würden rechtzeitig angekündigt.