Abundera QR Pro API
Referencia de la REST API de pro.qr.abundera.ai. Crea, edita y analiza códigos QR dinámicos de forma programática. Todo es JSON sobre HTTPS, autenticado mediante bearer token.
/docs/openapi.json, importa en Postman, Insomnia o cualquier cliente OpenAPI 3.1. Cubre 36 endpoints de cara al cliente: Códigos, Analíticas, Grupos, Equipos, Webhooks y Usuario. Los endpoints de administración e internos de Stripe se excluyen intencionalmente (solo servicio a servicio).Introducción
La API de Abundera QR Pro permite crear, editar y analizar códigos QR dinámicos de forma programática: todo lo que un desarrollador quiere automatizar desde el panel. La gestión de equipos, la facturación y los flujos de cuenta se quedan en la interfaz del panel; esta API está orientada a operaciones de código a nivel de desarrollador.
URL base: https://pro.qr.abundera.ai/api
Formato de solicitud: JSON (Content-Type: application/json) en POST / PATCH / DELETE.
Formato de respuesta: JSON (application/json; charset=utf-8).
Disponibilidad: El acceso a la API es una función de Business en adelante. Los planes Solo pueden usar el panel, pero no la API.
Autenticación
Cada solicitud lleva una clave API como bearer token:
Authorization: Bearer abnd_qrpro_...Crea y revoca claves en /account/keys (tier Business, Team o Agency). El token abnd_qrpro_... se muestra exactamente una vez al crearlo, guárdalo de inmediato. Solo almacenamos su hash SHA-256; no hay forma de recuperar una clave perdida.
Las solicitudes no autenticadas devuelven 401 { "error": "not_signed_in" }. Las claves inválidas o revocadas devuelven 401 { "error": "invalid_api_key" }.
Las claves API están vinculadas al usuario que las creó. Si ese usuario es miembro de un equipo, los endpoints siguientes operan automáticamente sobre los códigos del equipo (el contexto de equipo actual se almacena en la cuenta de usuario y se gestiona desde el panel).
Límites de tasa
Se aplican por clave API. Cada respuesta incluye X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset (segundos unix en los que se reinicia la ventana).
| Plan | Límite | Ventana |
|---|---|---|
| Business | 1.000 solicitudes / día | Día UTC |
| Team | 10.000 solicitudes / día | Día UTC |
| Agency | 50.000 solicitudes / día | Día UTC |
| Solo | (403 insufficient_plan) | , |
Las solicitudes que superan el presupuesto devuelven 429 { "error": "rate_limited", "window": "day", "retry_at": 1234567890 } con una cabecera Retry-After en segundos.
Los escaneos no tienen límite de tasa, la ruta de redirección (aqr.net/{shortcode}) no requiere autenticación ni presupuesto por escaneo. Cada plan tiene un límite mensual de escaneos explícito (100k / 1M / 10M / 30M). Si se supera, el redireccionamiento sigue funcionando; te enviamos un correo para que decidas si actualizar el plan o absorber el pico puntual. ¿Planeas superar ~10M de escaneos diarios? Escríbenos para coordinar capacidad.
Errores
Toda respuesta de error es JSON con un código error legible por máquina y, cuando corresponde, contexto adicional:
{ "error": "plan_limit", "plan": "business", "limit": 500, "current": 500 }| Estado | Código | Significado |
|---|---|---|
| 400 | validation_error | Un campo del cuerpo no superó la validación. La respuesta incluye field + message. |
| 401 | not_signed_in / invalid_api_key | Bearer token ausente, inválido o revocado. |
| 402 | plan_limit | Alcanzaste el límite de códigos activos+pausados de tu plan. La respuesta incluye plan, limit, current. |
| 402 | plan_expired | La cuenta superó los 90 días de gracia; actualiza el plan para reanudar. |
| 403 | insufficient_plan | El acceso a la API requiere Business o superior. Los usuarios Solo reciben este error. |
| 403 | insufficient_role | Tu rol en el equipo no permite la mutación solicitada (se requiere admin o superior). |
| 404 | not_found | El recurso no existe o no es visible en tu scope. |
| 409 | code_not_editable | El código está en estado de gracia o expirado; reactívalo para editarlo. |
| 429 | rate_limited | Presupuesto diario del plan superado. Ver Límites de tasa. |
| 500 | internal | Error de servidor no controlado, escribe a soporte si es reproducible. |
Códigos
Códigos QR dinámicos: un shortcode en Base58 de 7 caracteres que redirige a través de aqr.net/{shortcode}. Cada código incluye un QR estático de respaldo que puedes descargar desde el panel, si dejas de pagar, la versión estática sigue resolviendo sin tocar nuestra infraestructura.
GET /api/codes
Lista todos los códigos en tu scope actual (personal o el equipo bajo el que estás actuando). Devuelve un array con el resumen de escaneos de 30 días por código.
$ 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 campaign", "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
Crea un nuevo código dinámico. El límite de códigos activos+pausados del plan se verifica antes de insertar. Cuerpo mínimo:
{ "url": "https://example.com/landing" }Personalización completa (todo opcional):
{ "url": "https://example.com/landing",
"label": "Spring campaign",
"tags": "q2,print",
"qr_type": "url",
"style_json": "{...}",
"logo_key": "instagram",
"frame_style": "scan-me",
"frame_text": "SCAN ME" }Devuelve 201 + la fila creada, incluyendo el shortcode generado y la short_url que se imprime.
GET /api/codes/{id}
Obtiene un código individual. Devuelve 404 si no está en tu scope.
PATCH /api/codes/{id}
Actualiza cualquier campo mutable. El uso más habitual: cambiar la URL de destino de un código ya impreso.
$ curl -X PATCH -H "Authorization: Bearer abnd_qrpro_..." -H "Content-Type: application/json" -d '{"url":"https://example.com/new-landing"}' https://pro.qr.abundera.ai/api/codes/uuidLos cambios se propagan al redireccionamiento en segundos. Valores válidos de status para PATCH: "active", "paused". Para eliminar, usa DELETE.
DELETE /api/codes/{id}
Eliminación lógica. Pasa a status=grace con grace_until = now + 90 días. El redireccionamiento sigue funcionando durante todo el período de gracia, es el compromiso de no lock-in hecho tangible. Después de 90 días el código pasa a expired y el redireccionamiento devuelve 410 Gone.
POST /api/codes/import
Creación masiva desde un payload de array (también usado por el flujo "Guardar en Pro" de qr.abundera.ai). Acepta un payload de código único o un array. El límite del plan se verifica una vez antes del lote.
Analíticas
GET /api/codes/{id}/analytics
Parámetros de consulta:
range=7d|30d|90d|1y|3y, limitado a la retención de tu plan (Solo 1 año, Business 2 años, Team/Agency 3 años).granularity=day|hour, la granularidad horaria es solo para Team y Agency; ventana máxima de 7 días para datos horarios.
{
"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 }
]
}Los países con menos de 5 escaneos en la ventana se agrupan en "Other" por privacidad (ver Modelo de privacidad).
Claves API
Crea y revoca claves desde la página del panel /account/keys. La autogestión programática es de solo lectura mediante la API, puedes listar y revocar tus claves, pero crear una nueva requiere el panel (huevo y gallina: necesitarías una clave para crear otra).
GET /api/keys
Lista tus claves API. Nunca devuelve el token en crudo, solo metadatos.
{
"keys": [
{ "id": "uuid", "label": "Production server",
"created_at": 1713288000, "last_used_at": 1713370000 }
],
"allowed": true,
"plan": "business"
}DELETE /api/keys/{id}
Revoca la clave. Deja de funcionar de inmediato; cualquier solicitud que la use devolverá 401 invalid_api_key a partir de ese momento.
Exportación de datos
GET /api/user/export
Descarga un ZIP con tu conjunto de datos completo: codes.csv (todos los códigos, incluidos los de gracia y expirados), scans.csv (resumen diario agregado) y un README.txt que explica el formato. El archivo se emite como application/zip; redirige a un fichero:
$ curl -H "Authorization: Bearer abnd_qrpro_..." -o abundera-qr-export.zip https://pro.qr.abundera.ai/api/user/exportReimporta en cualquier sitio. Esta es la garantía de formato portable: no puede haber lock-in si tus datos son tuyos.
Modelo de privacidad
El agregado de escaneos es toda la historia de privacidad. Lo que almacenamos por escaneo en la ruta de redirección:
code_id, cuál de tus códigos fue escaneadoday_bucket, fecha UTC (YYYY-MM-DD). Sin precisión subdiaria en el agregado que se te devuelve.country, ISO-3166-1 alfa-2 de la cabeceraCF-IPCountryde Cloudflare. Sin ciudad, sin región, sin consulta de geo-IP.device_type,mobile/tablet/desktop/unknown, clasificado por una expresión regular breve sobre el User-Agent. La cadena de UA en crudo se descarta en el momento de la clasificación.scan_count, contador agregado, actualizado en cada visita.
Lo que no almacenamos: direcciones IP (ni hasheadas), cadenas User-Agent en crudo, geolocalización a nivel de ciudad, marcas de tiempo subdiarias, referer, cookies, píxeles de retargeting ni ningún vector identificador individual. Un umbral de ruido de 5 suprime los agregados pequeños para evitar la reidentificación.
Los tiers Team y Agency escriben además un agregado horario paralelo con hour_bucket (YYYY-MM-DD-HH UTC). El mismo modelo de privacidad, sin marcas de tiempo más finas que la hora, mismo umbral de ruido, misma ausencia de datos del escaneador individual.
Lee la historia completa: /manifesto/ y /no-lock-in/ en el sitio de la herramienta gratuita.