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_key400 invalid_body— casi siempre una URL que no lo es.402 plan_limit_reached429 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.