Saltar al contenido
QRflick

API REST y webhooks

Crea, cambia y consulta tus códigos QR dinámicos desde tu propio software, y recibe un webhook firmado cuando alguien escanea o deja sus datos.

URL base: https://qrflick.com/api/v1

Autenticación

Cada petición lleva una clave de API en la cabecera Authorization. Las claves pertenecen a una cuenta (o espacio de equipo) y las crea su propietario o un administrador en Ajustes → Desarrolladores.

curl https://qrflick.com/api/v1/me \
  -H "Authorization: Bearer api_…"
  • Las claves de solo lectura pueden listar y obtener códigos, tarjetas, contactos, escaneos e imágenes.
  • Las claves de lectura y escritura también pueden crear, cambiar y eliminar códigos y endpoints de webhook.
  • Una clave deja de funcionar si quien la creó sale del equipo o deja de ser administrador, o si la cuenta pasa a un plan sin API.

Crea una clave en Ajustes → Desarrolladores.

Peticiones, errores y límites

Envía y recibe JSON. Las fechas van en ISO 8601 y UTC. Los ids son los de 12 caracteres que ves en las URL del panel.

Las listas van paginadas: usa ?page= y ?per_page= (hasta 100). Las respuestas incluyen data, links y meta. Cada clave tiene un límite de peticiones por minuto; la cabecera X-RateLimit-Remaining muestra lo que queda.

EstadoSignificado
401Clave ausente, incorrecta o revocada.
403La clave es de solo lectura, el plan no incluye la API o la acción no está permitida.
404No existe ese registro en esta cuenta.
422Algo de la petición no es válido o supera un límite del plan; errors indica qué campo.
429Demasiadas peticiones. Espera los segundos de Retry-After.
{
  "message": "The name field is required.",
  "errors": { "name": ["The name field is required."] }
}

Endpoints

PeticiónQué hace
GET /me La cuenta, el plan, la clave y los límites. Útil para probar la conexión.
GET /qr-codes Tus códigos dinámicos, los más nuevos primero. Filtros: search, type, archived.
POST /qr-codes Crea un código: type, name, payload y, opcionalmente, design. (requiere lectura y escritura)
GET /qr-codes/{id} Un código, con su enlace corto, destino y número de escaneos.
PATCH /qr-codes/{id} Cambia name, payload, type, design o paused (true/false). El código impreso no cambia. (requiere lectura y escritura)
DELETE /qr-codes/{id} Elimina un código. Su enlace corto mostrará «no encontrado». (requiere lectura y escritura)
GET /qr-codes/{id}/image El código en png, svg, pdf o eps: ?format=, y ?size= (píxeles) o ?mm= y ?dpi=.
GET /qr-codes/{id}/scans Escaneos por día y desgloses (país, ciudad, dispositivo, sistema, navegador, idioma, origen): ?from= y ?to= (AAAA-MM-DD).
GET /cards Tus tarjetas de visita digitales.
GET /cards/{id} Una tarjeta, con su página y su enlace corto.
GET /cards/{id}/leads Contactos compartidos en una tarjeta, los más nuevos primero. ?since= devuelve solo los posteriores.
GET /webhooks Tus endpoints de webhook.
POST /webhooks Suscribe una URL a eventos (url, events). La respuesta incluye el secreto de firma. (requiere lectura y escritura)
DELETE /webhooks/{id} Da de baja un endpoint. (requiere lectura y escritura)

Ejemplo: crear y cambiar un código

Crea un código de sitio web. La respuesta trae el enlace corto para imprimir o compartir.

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"
  }
}

"domain" opcional: el dominio de redirección de la plataforma que tu espacio puede usar (los mismos que se ofrecen al crear un código en la app). Omítelo para el dominio corto estándar. La dirección no se puede cambiar por la API una vez creada.

Más adelante, lleva el mismo código impreso a otro sitio:

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"}}'

Descárgalo como SVG listo para imprenta, de 40 mm de ancho:

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

Tipos de código QR y campos del payload

El payload contiene los campos del tipo de código. Los códigos de tarjetas y perfiles se crean con su tarjeta o perfil, no aquí.

typeCampos del payload
url url*
whatsapp phone*, message
phone phone*
email email*, subject, body
sms phone*, message
maps query*
google_review place_id*
link_bio Pro title*, description, links*
menu Pro title*, description, menu_url*
app_store Pro ios_url*, android_url*, fallback_url*
event Pro title*, description, starts_at*, location, url
coupon Pro title*, description, code*, expires_at, url
social platform*, handle*
file title*, description, file_url

* obligatorio. Los tipos Pro requieren un plan con redirecciones inteligentes.

Webhooks

Añade un endpoint en Ajustes → Desarrolladores (o con POST /webhooks) y elige sus eventos. Cada evento se envía por POST en JSON:

EventoSe envía cuando
qr_code.createdSe creó un código QR.
qr_code.updatedUn código QR cambió de destino, estado o ajuste.
qr_code.deletedSe eliminó un código QR.
scan.createdAlguien escaneó un código (sin bots ni vistas previas de enlaces).
lead.createdAlguien compartió su contacto en una tarjeta o escribió desde un perfil.
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
  }
}
  • Responde con cualquier estado 2xx en menos de 10 segundos; haz el trabajo lento después de responder.
  • Cualquier otra respuesta se reintenta tras 1 min, 5 min, 30 min, 2 h, 6 h.
  • Si 20 eventos seguidos fallan en todos sus intentos, el endpoint se pausa y el propietario recibe un email.
  • Los reintentos y «Enviar de nuevo» mantienen el mismo webhook-id: úsalo para descartar duplicados.
  • Los escaneos nunca incluyen direcciones IP. Los eventos de contacto incluyen los datos que el visitante decidió compartir.

Comprobar las firmas

Los envíos se firman según Standard Webhooks. Firma «webhook-id.webhook-timestamp.cuerpo sin procesar» con HMAC-SHA256, usando la parte de tu secreto tras whsec_ decodificada en base64, y compárala con la cabecera webhook-signature. Rechaza marcas de tiempo antiguas para evitar repeticiones.

// 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
  && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));

Las librerías de Standard Webhooks (standardwebhooks.com) para la mayoría de lenguajes lo comprueban por ti.

Tu próxima conexión te espera.

Haz que tu próximo escaneo
sea el comienzo de algo.

Tu próximo cliente puede estar buscándote ya. Pónselo fácil.

Crea tu primer QR gratis Sin tarjeta. Sin caducidad. Solo posibilidades.