Saltearse al contenido

API de códigos QR

Descripción general

La API de códigos es el núcleo de qr3.app. Con ella puedes crear, actualizar y eliminar códigos QR dinámicos y estáticos.

URL base: https://qr3.app/v1/codes

Contrato REST vinculante

El siguiente contrato se aplica a todos los clientes:

  • POST /v1/codes acepta únicamente los tipos url, vcard, wifi, email, sms y location. Los campos son planos: url; al menos vcard_first_name o vcard_last_name; wifi_ssid; email_to; sms_phone; o ambos location_lat y location_lng.
  • Solo los códigos url pueden ser dinámicos. Las solicitudes de creación pueden incluir opcionalmente expires_at como marca de tiempo ISO 8601; ab_enabled, ab_target_url_b y ab_weight_a (destinos A/B) se aceptan para códigos url dinámicos; redirect_after_expiry no forma parte del contrato de creación.
  • GET /v1/codes admite solo limit, cursor y status (live, paused, flagged, draft).
  • POST /v1/codes/batch acepta url, vcard y wifi. El límite es 10 para Free, 500 para Pro y 1.000 registros para Business/Agency/Enterprise por solicitud. Los análisis de URL se ejecutan de forma síncrona para un máximo de 50 elementos URL; por encima de 50 se requiere skip_url_scan: true.

Crear código QR

POST /v1/codes

Ventana de terminal
curl -X POST https://qr3.app/v1/codes \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{
"type": "url",
"url": "https://example.com",
"title": "Mein erster QR-Code",
"tags": ["marketing", "q1"],
"is_dynamic": true
}'

Respuesta (HTTP 201):

{
"data": {
"id": "qr_a1b2c3d4",
"short_code": "r7f3Kx",
"redirect_url": "https://qr3.app/r7f3Kx",
"image_svg_url": "https://qr3.app/v1/codes/r7f3Kx/qr.svg",
"image_png_url": "https://qr3.app/v1/codes/r7f3Kx/qr.png",
"image_pdf_url": "https://qr3.app/v1/codes/r7f3Kx/qr.pdf",
"image_eps_url": "https://qr3.app/v1/codes/r7f3Kx/qr.eps",
"type": "url",
"target_url": "https://example.com",
"is_dynamic": true,
"status": "live",
"tags": ["marketing", "q1"],
"total_scans": 0,
"created_at": "2026-03-15T10:00:00.000Z"
},
"meta": { "request_id": "req_xyz123" }
}

Tipos de códigos QR

TipoDescripciónCampos obligatorios
urlURL del sitio web (dinámica o estática)url
vcardTarjeta de visita (vCard 3.0)vcard_first_name o vcard_last_name
wifiConfiguración Wi-Fiwifi_ssid
emailCorreo electrónico (mailto:)email_to
smsSMSsms_phone
locationUbicación (geo:)location_lat, location_lng

Creación por lotes

POST /v1/codes/batch

Ventana de terminal
curl -X POST https://qr3.app/v1/codes/batch \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "type": "url", "url": "https://produkt-1.example.com", "tags": ["batch"] },
{ "type": "url", "url": "https://produkt-2.example.com", "tags": ["batch"] },
{ "type": "wifi", "wifi_ssid": "GastWLAN", "wifi_password": "geheim123" }
],
"skip_url_scan": false
}'

Respuesta (HTTP 201):

{
"data": {
"created": [
{ "id": "qr_...", "short_code": "abc123", "redirect_url": "https://qr3.app/abc123" },
{ "id": "qr_...", "short_code": "def456", "redirect_url": "https://qr3.app/def456" },
{ "id": "qr_...", "short_code": "ghi789", "status": "live" }
],
"total": 3,
"failed": 0
}
}

Lista de códigos QR

GET /v1/codes

Ventana de terminal
curl https://qr3.app/v1/codes?status=live&limit=20 \
-H "Authorization: Bearer qr3_sk_..."

Parámetros de consulta:

ParámetroTipoPor defectoDescripción
cursorstring—Cursor para paginación
limitinteger20Resultados por página (máx. 100)
statusstring—Filtro: live, paused, flagged, draft

Obtener código QR

GET /v1/codes/:id

Ventana de terminal
curl https://qr3.app/v1/codes/qr_a1b2c3d4 \
-H "Authorization: Bearer qr3_sk_..."

Actualizar código QR

PATCH /v1/codes/:id

Update contract: url may be changed only for an existing type: "url" code, and its value must use http:// or https://. Other code types must not receive url; invalid requests return 422.

Los códigos QR dinámicos permiten cambiar la URL de destino en cualquier momento, sin tener que volver a imprimir el código QR.

Ventana de terminal
curl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4 \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{ "url": "https://neue-zielseite.example.com", "status": "live" }'

Landing page y enlaces externos

Para códigos url dinámicos, puedes establecer is_landing_page: true (al crearlos o mediante PATCH). Al escanearlos, se mostrará una página alojada por qr3 con los archivos públicos y enlaces externos del código, en lugar de redirigir. Los enlaces externos se envían como un array links:

{
"is_landing_page": true,
"links": [
{ "label": "Datenblatt", "url": "https://example.com/datenblatt.pdf" },
{ "label": "Zertifikat", "url": "https://example.com/zertifikat.pdf" }
]
}
  • Entre 0 y 20 enlaces por código; label debe tener de 1 a 100 caracteres; url debe ser http(s) (≤ 2048 caracteres).
  • Cada URL se comprueba con Google Web Risk; una URL no segura devuelve un error 422.
  • Si Web Risk no está disponible al guardar, el enlace se aceptará de todos modos, pero se marcará para una nueva comprobación. Una tarea diaria vuelve a comprobar los enlaces guardados (y reevalúa periódicamente los clasificados como seguros) y pausa el código automáticamente si un enlace se detecta más tarde como no seguro.
  • "links": [] elimina todos los enlaces. Consulta la guía de landing pages.

Eliminar código QR

DELETE /v1/codes/:id

Eliminación suave (Soft-Delete): el código QR se archiva y los datos de escaneo se conservan.

Un segundo DELETE del mismo código devuelve 404, incluso si ambas solicitudes llegan al mismo tiempo. El webhook qr.deleted se envía exactamente una vez.

Ventana de terminal
curl -X DELETE https://qr3.app/v1/codes/qr_a1b2c3d4 \
-H "Authorization: Bearer qr3_sk_..."

Descargar imágenes de QR

Todos los formatos de imagen son de acceso público; no se requiere autenticación.

FormatoURLUso
SVG (vectorial)/v1/codes/:code/qr.svgWeb, escalado, digital
PNG (rasterizado)/v1/codes/:code/qr.pngCorreo electrónico, presentaciones
PDF (vectorial)/v1/codes/:code/qr.pdfPor defecto: cuadrado (solo el código); ?format=a4 para una hoja de impresión
EPS (vectorial)/v1/codes/:code/qr.epsFlujos de trabajo de impresión profesional (Adobe, imprentas)

Opcional: ?size=N — Tamaño del módulo en píxeles (2–20, por defecto: 4) para SVG, PNG y EPS. El PDF utiliza un tamaño de módulo fijo.

Solo PDF: ?format=a4|square — Formato de página (por defecto: square — solo código + zona de silencio, sin espacio en blanco A4; a4 para una hoja A4 lista para imprimir)

Ventana de terminal
# SVG für Web
curl https://qr3.app/v1/codes/r7f3Kx/qr.svg
# PNG in hoher Auflösung
curl https://qr3.app/v1/codes/r7f3Kx/qr.png?size=10 -o qr-hires.png
# Kompaktes PDF (nur der Code, Standard)
curl https://qr3.app/v1/codes/r7f3Kx/qr.pdf -o qr.pdf
# Druckfertiges A4-Blatt
curl "https://qr3.app/v1/codes/r7f3Kx/qr.pdf?format=a4" -o qr-a4.pdf

Colores y corrección de errores

Las cuatro rutas de imagen aceptan tres parámetros opcionales. Se aplican a esa solicitud específica y tienen prioridad sobre los colores guardados en el código (siguiente sección).

ParámetroValoresPredeterminadoSVG, PNGPDF, EPS
fgHex RRGGBB o RGB000000se dibujase dibuja como color de impresión
bgHex como fg o transparentffffffse dibujase dibuja como color de impresión
eccL, M, Q, HMse aplicase aplica
  • Formato: No distingue entre mayúsculas y minúsculas, el # es opcional. Si se incluye, debe codificarse como %23.
  • Los valores no válidos cuentan como no establecidos. ?fg=lila devuelve el color guardado en el código, o el negro normal si no hay ninguno guardado, con 200 y nunca un error. Solo un ?fg=000000 explícito fuerza el negro.
  • bg=transparent devuelve un SVG, PDF o EPS sin fondo y un PNG con canal alfa real. La superficie sobre la que se coloque el código debe ser clara y dejar una zona de silencio de 4 módulos alrededor. Un código oscuro sobre un fondo oscuro no es legible.
  • PDF y EPS escriben el negro y el gris como escala de grises (solo la placa negra) y cualquier otro color como CMYK en porcentajes enteros, por ejemplo 1F4E79 como C74 M36 Y0 K53. En cuanto se elige un color, un fondo opaco se sitúa detrás del código y su zona de silencio, en blanco o en el color de bg, al igual que en el SVG. Sin colores, ambos archivos permanecen sin cambios. Conversión y límites: Colores en la impresión.
  • Contraste: La ruta de la imagen no lo comprueba. Se recomienda un mínimo de 4:1 y módulos oscuros sobre fondo claro. #1F4E79 sobre blanco tiene 8,7:1, #ff6600 sobre blanco solo 2,9:1.
  • ecc cambia el patrón de puntos, no el contenido. Un código impreso seguirá funcionando, pero no se deben mezclar archivos de impresión antiguos y nuevos. Q o H hacen que el código sea más robusto, por ejemplo, en cartón ondulado. Un logotipo siempre fuerza H.
  • Con logotipo el área detrás del logotipo permanece blanca, incluso con un fondo de color o transparente.
  • Caché: solo la imagen estándar real (negro sobre blanco, corrección de errores M, sin logotipo) se entrega como inmutable durante 24 horas; cualquier otra representación durante 5 minutos. Para PDF y EPS, cualquier fondo especificado cuenta como una desviación: bg=ffffff dibuja allí un relleno blanco que el archivo estándar no tiene.
  • Plan: Los colores y la corrección de errores están disponibles en todos los planes, incluido el gratuito.
Ventana de terminal
# Dark blue code on white
curl "https://qr3.app/v1/codes/r7f3Kx/qr.svg?fg=1F4E79" -o qr-blue.svg
# Transparent PNG for a layout on a light surface
curl "https://qr3.app/v1/codes/r7f3Kx/qr.png?size=10&bg=transparent" -o qr-transparent.png
# More robust for corrugated board: error correction Q
curl "https://qr3.app/v1/codes/r7f3Kx/qr.pdf?ecc=Q" -o qr-q.pdf

Guardar colores en el código

PATCH /v1/codes/:id guarda los colores como appearance en el código. Las rutas de imagen los dibujan por defecto, sin parámetros.

Ventana de terminal
curl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4 \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{"appearance": {"foreground_color": "#1F4E79"}}'

Respuesta (HTTP 200, abreviada):

{
"data": {
"id": "qr_a1b2c3d4",
"short_code": "r7f3Kx",
"appearance": { "foreground_color": "#1F4E79", "background_color": null }
},
"meta": { "request_id": "req_xyz", "issues": [] }
}
  • Valores: foreground_color como #RRGGBB, background_color como #RRGGBB o transparent. Otras claves devuelven 400.
  • Combinación: Un campo omitido conserva su valor guardado. null restablece un campo, "appearance": null ambos. El negro y el blanco no se guardan; la respuesta los muestra como null.
  • Cada respuesta de código contiene appearance, al igual que los webhooks qr.created y qr.updated.
  • Orden de prioridad en las rutas de imagen: primero el parámetro, luego el color guardado, luego el valor por defecto. Por lo tanto, ?fg=000000 devuelve el archivo de impresión en negro de un código de color.
  • Imágenes incrustadas: Una URL de imagen sigue los colores guardados, siempre que no los establezca por sí misma con fg y bg: una URL sin parámetros para ambos colores, ?fg=000000 para el fondo, ?ecc=Q también para ambos. Después de un cambio de color, una página que incruste dicha URL aún puede mostrar la imagen antigua: hasta 24 horas si la URL entregaba la imagen predeterminada hasta entonces (negro sobre blanco, corrección de errores M, sin logo), de lo contrario hasta 5 minutos. La solución es un parámetro propio en la URL que cambie con cada cambio de color, como ?v=2 o el updated_at del código como en el Dashboard. Las rutas de imagen ignoran los parámetros desconocidos.
  • La corrección de errores nunca se guarda. Se selecciona para cada descarga con ?ecc=.
  • Solo mediante PATCH: POST /v1/codes, el lote y la importación rechazan appearance con 422.
  • PDF y EPS dibujan los colores guardados como colores de impresión, al igual que los parámetros. Como el blanco nunca se guarda, un código con un color de primer plano guardado obtiene un relleno blanco allí, al igual que en el SVG.

Verificación de contraste

La API verifica el par resultante de la solicitud y el valor guardado:

NivelCuándoRespuesta
blockedContraste inferior a 1,5:1422, no se guarda nada
criticalinferior a 2:1 o diferencia de luminosidad inferior a 0,30; una advertencia junto con un logotipo; cualquier fondo transparente200 con meta.issues
warninginferior a 4:1 o diferencia de luminosidad inferior a 0,50; módulos claros sobre fondo oscuro200 con meta.issues
okcualquier otro caso200, meta.issues está vacío

Cada entrada en meta.issues tiene code, severity, field, message y, opcionalmente, hints como contrast_ratio, con el mismo formato que los mensajes de conformidad de un pasaporte digital de producto. Un fondo transparente nunca se bloquea, ya que un código claro sobre un embalaje oscuro es un caso de uso real. No obstante, el fondo sigue necesitando un contraste claro y una zona de silencio despejada de 4 módulos a su alrededor.

Subir y eliminar un logotipo (POST y DELETE /v1/codes/:id/logo) realizan la misma comprobación en los colores guardados y también devuelven los resultados en meta.issues: con un logotipo una advertencia pasa a ser critical, sin él vuelve a ser una advertencia.

Si otra solicitud modifica el mismo código en el mismo instante, la API aplica los cambios a la última versión. Solo si esto falla tres veces consecutivas, responderá con 409; en ese caso, el cliente vuelve a cargar el código y repite la modificación.


Solicitud multipart, campo file: PNG, JPEG o WebP, máximo 1 MB, detectado por los bytes mágicos. Normaliza la imagen a un PNG transparente de 512×512 y reemplaza un logo existente.

Ventana de terminal
curl -X POST https://qr3.app/v1/codes/qr_a1b2c3d4/logo \
-H "Authorization: Bearer qr3_sk_..." \

Antwort (HTTP 201): el código actualizado, con logo_file_id establecido.

Elimina el logo y borra el objeto almacenado. Idempotente — una llamada sin un logo existente sigue devolviendo 200.

Si otra solicitud cambia el logo del mismo código en el mismo instante (una segunda subida o una eliminación), POST y DELETE /v1/codes/:id/logo responden con 409 (errors/conflict) y no cambian nada; la imagen subida se descarta. Vuelve a cargar el código e inténtalo de nuevo. Dos llamadas simultáneas de DELETE /v1/codes/:id/logo no son un conflicto; ambas devuelven 200.

Si está establecido, los cuatro formatos — qr.svg, qr.png, qr.pdf y qr.eps — incrustan los píxeles del logo y elevan la corrección de errores a H. El contrato completo — incluyendo qué cambio (añadir/eliminar vs. reemplazar) modifica el patrón de puntos — así como las instrucciones de impresión se encuentran en Logo en el código QR.


Comentarios

Los comentarios permiten ciclos de retroalimentación entre agencias y clientes.

GET /v1/codes/:id/comments

POST /v1/codes/:id/comments

PATCH /v1/codes/:id/comments/:commentId

DELETE /v1/codes/:id/comments/:commentId

Los comentarios del dashboard se atribuyen al usuario creador (author_id); los comentarios creados a través de API-keys puras permanecen sin atribuir (author_id: null). Solo el propio autor o un org_admin/ws_admin puede eliminar un comentario; las API-keys puras solo pueden eliminar comentarios de la API que no estén atribuidos.

Ventana de terminal
# Kommentar hinzufügen
curl -X POST https://qr3.app/v1/codes/qr_a1b2c3d4/comments \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{ "body": "QR-Code bitte auf grünen Hintergrund abstimmen.", "author_name": "Max Müller" }'
# Offene Kommentare auflisten
curl "https://qr3.app/v1/codes/qr_a1b2c3d4/comments?resolved=false" \
-H "Authorization: Bearer qr3_sk_..."
# Kommentar als erledigt markieren
curl -X PATCH https://qr3.app/v1/codes/qr_a1b2c3d4/comments/cmt_xyz \
-H "Authorization: Bearer qr3_sk_..." \
-H "Content-Type: application/json" \
-d '{ "resolved": true }'