Vai al contenuto principale
Sviluppatori

API DenQr

Ultimo aggiornamento: 18 settembre 2026

L’API REST di DenQr fa tutto quello che fa la dashboard: creare QR Code statici e dinamici, cambiare la destinazione di un dinamico senza ristampare, leggere le statistiche, ricevere le scansioni in tempo reale via webhook. Base URL: https://api.denqr.com/api/v1. Tutte le risposte sono JSON.

L’API è inclusa dal piano Starter (500 richieste al mese, 60 al minuto), Pro (3.000 al mese, 120 al minuto), Business ed Enterprise (senza tetto mensile). Il contatore si azzera il primo del mese; lo vedi in Dashboard → API & Webhook.

1. Autenticazione

Chiave API

Crea una chiave da Dashboard → API & Webhook → Chiavi API. Ha il formato dq_…, si mostra una sola volta e può essere di sola lettura o di lettura e scrittura. Passala nell’header Authorization:

curl https://api.denqr.com/api/v1/qr \
  -H "Authorization: Bearer dq_xxxxxxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"

Una chiave lavora sull’organizzazione che l’ha creata. Le rotte di fatturazione, account e pannello staff non sono raggiungibili con una chiave.

OAuth 2.0 (app di terzi)

Se il tuo software deve agire per conto di altri utenti DenQr, registra un’app da Dashboard → API & Webhook → App OAuth e usa il flusso Authorization Code con PKCE. Scope disponibili: read e write.

1. Manda l'utente a
   https://denqr.com/oauth/authorize?response_type=code
     &client_id=CLIENT_ID&redirect_uri=https://tuaapp.it/callback
     &scope=read%20write&state=STATO
     &code_challenge=BASE64URL(SHA256(verifier))&code_challenge_method=S256

2. L'utente autorizza e torna su redirect_uri?code=…&state=…

3. Scambia il codice con i token (form-urlencoded o JSON):
   POST https://api.denqr.com/api/v1/oauth/token
   grant_type=authorization_code&code=…&redirect_uri=…
   &client_id=…&code_verifier=…        # app pubbliche (PKCE)
   &client_secret=…                     # in alternativa, app server

   → { "access_token": "dqo_…", "token_type": "Bearer", "expires_in": 3600,
       "refresh_token": "dqr_…", "scope": "read write" }

4. Rinnova con grant_type=refresh_token&refresh_token=dqr_…&client_id=…
   (il refresh token vecchio viene invalidato: usa sempre l'ultimo ricevuto)

5. Revoca: POST https://api.denqr.com/api/v1/oauth/revoke  token=…&client_id=…

I token dqo_… si usano come una chiave API. Le richieste contano nella quota dell’organizzazione che ha autorizzato l’app.

2. QR Code

  • GET /qr — elenco, con search, status, type, mode, folderId, sort, page, perPage
  • POST /qr — crea un QR Code
  • GET /qr/:id — dettaglio
  • PATCH /qr/:id — modifica nome, cartella, scadenza, password, UTM…
  • POST /qr/:id/destination — cambia la destinazione di un dinamico (body: { payload, rules? })
  • PATCH /qr/:id/design — cambia colori, forma, logo, cornice
  • POST /qr/:id/duplicate — duplica
  • POST /qr/:id/archive — sposta nel cestino (i dinamici smettono di rispondere)
  • POST /qr/:id/restore — ripristina dal cestino
  • DELETE /qr/:id — elimina definitivamente
  • GET /qr/:id/export?format=png|svg|pdf&size=1024 — scarica il file
  • GET /qr/types — tipi disponibili con i campi del payload (pubblica)

Creare un QR

POST https://api.denqr.com/api/v1/qr
Content-Type: application/json

{
  "name": "Menu tavolo 4",
  "type": "url",              // vedi GET /qr/types: url, text, email, wifi, vcard, menu, …
  "mode": "dynamic",          // "static" = contenuto dentro al codice, non modificabile
  "payload": { "url": "https://esempio.it/menu" },
  "folderId": null,           // opzionale
  "expiresAt": null,          // opzionale, ISO 8601
  "maxScans": null,           // opzionale
  "utm": { "utm_source": "tavolo" },   // opzionale
  "design": { "foreground": "#0C1B29", "pattern": "rounded" }   // opzionale
}

→ 200 { "qr": { "id": "…", "shortCode": "waiTH7J", "shortUrl": "https://qr.denqr.com/waiTH7J", … } }

Un QR dinamico passa da qr.denqr.com: puoi cambiarne la destinazione dopo la stampa e ricevi le statistiche. Conta nella quota di QR dinamici del piano.

3. Cartelle e statistiche

  • GET /folders — elenco cartelle
  • POST /folders — crea (body: { name })
  • PATCH /folders/:id — rinomina
  • DELETE /folders/:id — elimina (i QR restano, senza cartella)
  • GET /analytics/overview?from&to&qrId&country&device — scansioni totali, uniche, serie giornaliera, paesi, dispositivi
  • GET /analytics/qr/:id?from&to — statistiche di un singolo QR
  • GET /analytics/export?from&to — CSV delle scansioni

4. Webhook

Da Dashboard → API & Webhook → Webhook (o via API su /developer/hooks) registri un URL https pubblico e scegli gli eventi. Per ognuno ricevi un POST JSON:

POST https://tuoserver.it/denqr
Content-Type: application/json
X-DenQr-Event: qr.scanned
X-DenQr-Delivery: cmu5rgifh000qlt11shx4obxl
X-DenQr-Signature: t=1789660419,v1=5f1a…

{
  "id": "cmu5rgifh000plt11ofyznmy4",
  "type": "qr.scanned",
  "created_at": "2026-09-17T16:45:31.086Z",
  "data": {
    "qr_id": "…", "short_code": "waiTH7J", "scanned_at": "…", "unique": true,
    "country": "IT", "city": "Milano", "device": "mobile", "os": "iOS", "browser": "Safari",
    "referrer": null, "utm": null
  }
}

Eventi

  • qr.created, qr.updated, qr.destination_changed, qr.archived, qr.deleted
  • qr.scanned — ogni scansione di un QR dinamico, senza dati personali (niente IP)

Verificare la firma

Calcola HMAC-SHA256(segreto, t + "." + corpo_grezzo) e confrontalo con v1 in modo a tempo costante; rifiuta se t è più vecchio di 5 minuti. Il segreto (whsec_…) lo vedi una sola volta alla creazione del webhook.

// Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';

function verifica(segreto, header, corpo) {
  const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const atteso = createHmac('sha256', segreto).update(`${t}.${corpo}`).digest('hex');
  return timingSafeEqual(Buffer.from(atteso), Buffer.from(v1));
}

Consegna e retry

Rispondi 2xx entro 10 secondi. Altrimenti riproviamo 5 volte con attese crescenti (1 min, 5 min, 30 min, 2 h, 12 h). Dopo 20 consegne fallite di fila il webhook si spegne da solo: lo riattivi dalla dashboard. Ogni evento e ogni tentativo restano visibili 30 giorni nel tab Eventi.

5. Errori e limiti

Gli errori hanno sempre la forma { "error": { "code": "…", "message": "…", "details": {} } }.

  • 401 UNAUTHENTICATED — chiave o token mancanti, non validi, revocati o scaduti
  • 403 FORBIDDEN — scope insufficiente (serve write) o rotta non disponibile via API
  • 403 FEATURE_NOT_AVAILABLE — funzione non inclusa nel piano
  • 422 VALIDATION_FAILED — campi mancanti o non validi (details spiega quali)
  • 404 QR_NOT_FOUND / NOT_FOUND
  • 429 RATE_LIMITED — troppe richieste al minuto
  • 403 QUOTA_EXCEEDED — quota mensile o limite del piano raggiunto

Domande o bisogno di più richieste? Scrivi a supporto@denqr.com.