Abundera QR Pro API
REST API-referentie voor pro.qr.abundera.ai. Maak, bewerk en analyseer dynamische QR-codes programmatisch. Alles is JSON over HTTPS, geverifieerd via bearer-token.
/docs/openapi.json, importeer in Postman, Insomnia of een andere OpenAPI 3.1-client. Dekt 36 klantgerichte endpoints voor Codes, Analytics, Groups, Teams, Webhooks en User. Admin- en Stripe-webhook-endpoints zijn bewust uitgesloten (service-to-service alleen).Inleiding
Met de Abundera QR Pro API maak, bewerk en analyseer je dynamische QR-codes programmatisch, alles wat een ontwikkelaar wil automatiseren vanuit het dashboard. Teambeheer, facturering en accountstromen blijven in de dashboard-UI; deze API is gericht op code-operaties op ontwikkelaarsniveau.
Basis-URL: https://pro.qr.abundera.ai/api
Verzoekformaat: JSON (Content-Type: application/json) bij POST / PATCH / DELETE.
Antwoordformaat: JSON (application/json; charset=utf-8).
Beschikbaarheid: API-toegang is een Business+-functie. Solo-abonnees kunnen het dashboard gebruiken, maar niet de API.
Authenticatie
Elk verzoek bevat een API-sleutel als bearer-token:
Authorization: Bearer abnd_qrpro_...Maak sleutels aan bij /account/keys (Business, Team of Agency). De ruwe abnd_qrpro_...-token wordt precies één keer getoond bij aanmaken, sla hem direct op. Wij slaan alleen de SHA-256-hash op; een verloren sleutel is niet terug te halen.
Niet-geverifieerde verzoeken krijgen 401 { "error": "not_signed_in" }. Ongeldige of ingetrokken sleutels krijgen 401 { "error": "invalid_api_key" }.
API-sleutels zijn gekoppeld aan de gebruiker die ze heeft aangemaakt. Als die gebruiker lid is van een team, werken de onderstaande endpoints automatisch op de codes van dat team (de huidige teamcontext is opgeslagen op het gebruikersaccount en beheerd via het dashboard).
Limieten
Gehandhaafd per API-sleutel. Elk antwoord bevat X-RateLimit-Limit, X-RateLimit-Remaining en X-RateLimit-Reset (unix-seconden waarop het venster herstart).
| Abonnement | Limiet | Venster |
|---|---|---|
| Business | 1.000 verzoeken / dag | UTC-dag |
| Team | 10.000 verzoeken / dag | UTC-dag |
| Agency | 50.000 verzoeken / dag | UTC-dag |
| Solo | (403 insufficient_plan) | , |
Verzoeken die het budget overschrijden, krijgen 429 { "error": "rate_limited", "window": "day", "retry_at": 1234567890 } met een Retry-After-header in seconden.
Scans zijn niet gelimiteerd, het redirect-pad (aqr.net/{shortcode}) vereist geen authenticatie en heeft geen scan-budget. Elk abonnement heeft een expliciet maandelijks scan-cap (100k / 1M / 10M / 30M). Overschrijd je het cap, dan blijft de redirect gewoon werken; wij sturen je een e-mail zodat je kunt beslissen of je wilt upgraden of de piek accepteert. Plannen boven ~10M dagelijkse scans? Mail ons om capaciteit af te stemmen.
Fouten
Elke foutrespons is JSON met een machine-leesbare error-code en, waar relevant, aanvullende context:
{ "error": "plan_limit", "plan": "business", "limit": 500, "current": 500 }| Status | Code | Betekenis |
|---|---|---|
| 400 | validation_error | Veldinvoer mislukt validatie. Antwoord bevat field + message. |
| 401 | not_signed_in / invalid_api_key | Ontbrekende, ongeldige of ingetrokken bearer-token. |
| 402 | plan_limit | Op het code-cap van je abonnement. Antwoord bevat plan, limit, current. |
| 402 | plan_expired | Account is voorbij het 90-daagse respijtvenster; upgrade om te hervatten. |
| 403 | insufficient_plan | API-toegang vereist Business of hoger. Solo-gebruikers raken dit. |
| 403 | insufficient_role | Je teamrol staat de gevraagde mutatie niet toe (admin+ vereist). |
| 404 | not_found | Resource bestaat niet, of is niet zichtbaar in je scope. |
| 409 | code_not_editable | De code heeft de status grace of expired; activeer opnieuw om te bewerken. |
| 429 | rate_limited | Per-plan daily budget exceeded. See Limieten. |
| 500 | internal | Onverwerkte serverfout, mail support als het reproduceerbaar is. |
Codes
Dynamische QR-codes: een 7-teken Base58-shortcode die omleidt via aqr.net/{shortcode}. Elke code heeft een statische reservekopie die je kunt downloaden via het dashboard, als je ooit stopt met betalen, werkt de statische versie nog steeds zonder onze redirect.
GET /api/codes
Geeft alle codes in je huidige scope (persoonlijk, of het team waaronder je nu werkt). Geeft een array terug met een 30-daagse scan-samenvatting per code.
$ curl -H "Authorization: Bearer abnd_qrpro_..." \
https://pro.qr.abundera.ai/api/codes
{
"codes": [
{ "id": "uuid", "shortcode": "aBc123x",
"url": "https://example.com/landing",
"label": "Q2 campagne", "tags": "q2,print",
"status": "active", "scans_30d": 1245,
"created_at": 1713288000, "updated_at": 1713370000 }
],
"plan": "business",
"plan_limit": 500,
"scope": { "type": "user" }
}POST /api/codes
Maak een nieuwe dynamische code aan. Het actieve+gepauzeerde code-cap van je abonnement wordt gecontroleerd vóór de invoeging. Minimale body:
{ "url": "https://example.com/landing" }Full customization (all optional):
{ "url": "https://example.com/landing",
"label": "Voorjaarscampagne",
"tags": "q2,print",
"qr_type": "url",
"style_json": "{...}",
"logo_key": "instagram",
"frame_style": "scan-me",
"frame_text": "SCAN ME" }Geeft 201 terug + de aangemaakte rij inclusief de gegenereerde shortcode en de short_url die je afdrukt.
GET /api/codes/{id}
Haal een enkele code op. 404 als niet in je scope.
PATCH /api/codes/{id}
Werk een muteerbaar veld bij. Meest voorkomend: wijzig de bestemmings-URL van een al afgedrukte code.
$ curl -X PATCH \
-H "Authorization: Bearer abnd_qrpro_..." \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/nieuwe-landing"}' \
https://pro.qr.abundera.ai/api/codes/uuidWijzigingen verspreiden zich binnen seconden naar de redirect. Geldige status-waarden voor PATCH: "active", "paused". Gebruik DELETE om te verwijderen.
DELETE /api/codes/{id}
Zachte verwijdering. Zet over naar status=grace met grace_until = nu + 90 dagen. De redirect blijft werken tijdens het volledige respijtvenster, dit is de no-lock-in prijsbelofte in de praktijk. Na 90 dagen wordt de code expired en geeft de redirect 410 Gone terug.
POST /api/codes/import
Bulk aanmaken via een array-payload (ook gebruikt door de "Opslaan in Pro"-stroom op qr.abundera.ai). Accepteert een enkele of een reeks code-payloads. Het abonnementslimiet wordt één keer gecontroleerd vóór de batch.
Analytics
GET /api/codes/{id}/analytics
Query-parameters:
range=7d|30d|90d|1y|3y, beperkt tot de retentie van je abonnement (Solo 1j, Business 2j, Team/Agency 3j).granularity=day|hour, uurlijks is alleen voor Team en Agency; maximaal 7-daags venster voor uurlijks.
{
"range": "30d", "days": 30, "granularity": "day",
"total": 4321,
"timeseries": [
{ "bucket": "2026-04-01", "scans": 142 },
{ "bucket": "2026-04-02", "scans": 178 },
...
],
"by_country": [
{ "key": "US", "total": 3012 },
{ "key": "CA", "total": 402 },
{ "key": "Other", "total": 108 }
],
"by_device": [
{ "key": "mobile", "total": 3850 },
{ "key": "tablet", "total": 312 },
{ "key": "desktop", "total": 159 }
]
}Countries with fewer than 5 scans in the window are folded into "Other" for privacy (see Privacymodel).
API-sleutels
Maak en trek sleutels in via de /account/keys-dashboardpagina. Programmatisch zelfbeheer is alleen-lezen via de API, je kunt je sleutels opvragen en intrekken, maar voor het aanmaken van een nieuwe sleutel heb je het dashboard nodig.
GET /api/keys
Geeft je API-sleutels weer. Geeft nooit de ruwe token terug, alleen metagegevens.
{
"keys": [
{ "id": "uuid", "label": "Productieserver",
"created_at": 1713288000, "last_used_at": 1713370000 }
],
"allowed": true,
"plan": "business"
}DELETE /api/keys/{id}
Intrekken. De sleutel werkt onmiddellijk niet meer; elk verzoek dat hem draagt, geeft daarna 401 invalid_api_key terug.
Data-export
GET /api/user/export
Download een ZIP met je volledige dataset, codes.csv (alle codes, inclusief grace + expired), scans.csv (samengevoegde dagelijkse rollup) en een README.txt die het formaat uitlegt. Het archief wordt opgeleverd als application/zip; sla het op in een bestand:
$ curl -H "Authorization: Bearer abnd_qrpro_..." \
-o abundera-qr-export.zip \
https://pro.qr.abundera.ai/api/user/exportImporteer overal opnieuw. Dit is de portable-formaat-garantie, vendor lock-in is onmogelijk als je je eigen data bezit.
Privacymodel
Het scan-aggregaat is het volledige privacyverhaal. Wat we per scan opslaan op het redirect-hotpad:
code_id, welke van je codes werd gescandday_bucket, UTC-datum (YYYY-MM-DD). Geen sub-dag precisie in het samengevoegde resultaat.country, ISO-3166-1 alpha-2 van Cloudflare'sCF-IPCountry-header. Geen stad, geen regio, geen geo-IP-lookup.device_type,mobile/tablet/desktop/unknown, geclassificeerd via een korte User-Agent-regex. De ruwe UA-string wordt weggegooid bij classificatie.scan_count, samengevoegde teller, geüpsert bij elke hit.
Wat we niet opslaan: IP-adressen (gehasht of anderszins), ruwe User-Agent-strings, stadsgeografie, sub-dag tijdstempels, referer, cookies, retargeting-pixels of enige individuele identificatievector. Een ruisdrempel van 5 onderdrukt heridentificatie bij kleine aggregaten.
Team- en Agency-abonnementen schrijven daarnaast een parallel uurlijks aggregaat met hour_bucket (YYYY-MM-DD-HH UTC). Hetzelfde privacymodel, geen fijnere tijdstempels dan uur, dezelfde ruisdrempel, hetzelfde gebrek aan individuele scannergegevens.
Lees het volledige verhaal: /manifesto/ en /no-lock-in/ op de gratis-tool-site.