Enqre

Por el equipo de Enqre·Publicado el 16/8/2026

Códigos QR dinámicos desde Python, Node y C#

Cada uno de estos lenguajes tiene una buena biblioteca local: qrcode para Python, node-qrcode para Node, QRCoder para .NET. Dibujan PNG y SVG sin conexión, sin clave, sin cuota y sin coste — y para un código cuyo destino nunca cambia, esa es toda la respuesta.

La API es para la otra mitad: un código estático es su destino — la URL está en el patrón, y moverla obliga a reimprimir todo. Si lo que generas se va a imprimir, pegar en una máquina o asociar a un registro que sobrevivirá a la estructura de URL de este año, el código debe llevar una dirección corta que controles. Eso es alojamiento, no dibujo.

Crear un código

Python

import os, requests

r = requests.post(
    "https://enqre.com/api/v1/qrcodes",
    headers={"Authorization": f"Bearer {os.environ['ENQRE_API_KEY']}"},
    json={
        "name": "Asset 4471 – service log",
        "url": "https://maint.example/assets/4471",
    },
    timeout=10,
)
r.raise_for_status()          # 4xx and 5xx become exceptions, not silence

code = r.json()["data"]
code["id"]        # store this against your record
code["shortUrl"]  # the address the QR image should encode

Node

const res = await fetch("https://enqre.com/api/v1/qrcodes", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ENQRE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Asset 4471 – service log",
    url: "https://maint.example/assets/4471",
  }),
});

// fetch does NOT throw on 4xx. Check the status or you will store undefined.
if (!res.ok) throw new Error(`enqre: ${res.status} ${await res.text()}`);

const { data: code } = await res.json();

Fíjate en la comprobación: fetch no falla ante un 402 ni un 429; sin ella guardas undefined.

C#

using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("ENQRE_API_KEY"));

var payload = JsonContent.Create(new {
    name = "Asset 4471 – service log",
    url  = "https://maint.example/assets/4471",
});

var res = await http.PostAsync("https://enqre.com/api/v1/qrcodes", payload);
res.EnsureSuccessStatusCode();

using var doc = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
var code = doc.RootElement.GetProperty("data");
var id       = code.GetProperty("id").GetString();
var shortUrl = code.GetProperty("shortUrl").GetString();

Mover el destino

PATCH https://enqre.com/api/v1/qrcodes/{id}
Authorization: Bearer enq_…
Content-Type: application/json

{ "url": "https://maint.example/assets/4471/v2" }

El código impreso no se toca; el siguiente escaneo va a otro sitio.

Leer los escaneos

GET /api/v1/qrcodes/{id}/scans responde { total, data }, del más reciente, hasta 1.000 registros: hora, tipo de dispositivo, sistema, navegador.

Ni identidad ni ubicación: ni ciudad ni país.

Qué va a fallar de verdad

  • 401 invalid_api_key
  • 400 invalid_body — casi siempre una URL que no lo es.
  • 402 plan_limit_reached
  • 429 rate_limited — más de 60 peticiones por minuto.

Cada lenguaje esconde el fallo de otra forma: requests calla sin raise_for_status, fetch solo rechaza por error de red, HttpClient necesita EnsureSuccessStatusCode.

Dos reglas que valen más que el código

Haz la creación idempotente. Dos llamadas crean dos códigos.

No imprimas lo que no has releído.

Cuándo no escribir integración

Para unos cientos de códigos una sola vez, la subida de CSV es más rápida que cualquier código que escribas.

Respuestas rápidas

  • ¿Mejor biblioteca? qrcode, node-qrcode, QRCoder.
  • ¿La API devuelve imagen? No, shortUrl.
  • ¿Autenticación? Authorization: Bearer enq_….
  • ¿Límite? 60 por minuto.
  • ¿Ubicación en los escaneos? No.
  • ¿Se puede cambiar tras imprimir? Es justo el objetivo — PATCH.

Sigue leyendo