APIPreciosDocumentaciónBlogSociosContacto
Volver al blog
Tutorial

De Herramienta Interna a Producto API: La Historia de PunchConnect

Cómo transformamos una integración biométrica interna construida para 24,000 empleados en un producto API REST cloud — y qué aprendimos en el camino.

PunchConnect Team·Mar 28, 2026·5 min read

Introduction

PunchConnect no estaba destinado a ser un producto. Nació de la frustración — y 4 meses de producción intensiva.

Estábamos construyendo AgriWise, una plataforma de gestión de personal para empresas agrícolas en Marruecos. 24,000+ empleados en decenas de sitios. Cada sitio tenía relojes checadores biométricos ZKTeco. Y necesitábamos obtener los datos de asistencia en tiempo real en nuestra aplicación cloud.

Nada en el mercado funcionaba. Así que lo construimos nosotros mismos.

El Problema Que Lo Inició Todo

<svg viewBox="0 0 700 300" xmlns="http://www.w3.org/2000/svg" style="max-width:700px;width:100%;font-family:system-ui,sans-serif">
<rect width="700" height="300" fill="#1a1a2e" rx="12"/>
<text x="350" y="30" fill="#e0e0e0" font-size="17" font-weight="bold" text-anchor="middle">Lo Que Intentamos (y Por Qué Falló)</text>
<rect x="30" y="55" width="195" height="110" rx="8" fill="#3e1e1e" stroke="#ef5350" stroke-width="1"/>
<text x="127" y="80" fill="#ef5350" font-size="15" font-weight="bold" text-anchor="middle">SDKs Open-Source</text>
<text x="127" y="105" fill="#ccc" font-size="14" text-anchor="middle">pyzk, node-zklib</text>
<text x="127" y="125" fill="#ccc" font-size="14" text-anchor="middle">Solo LAN, sin cloud</text>
<text x="127" y="145" fill="#ef5350" font-size="14" text-anchor="middle">❌ Falló con 10 dispositivos</text>
<rect x="252" y="55" width="195" height="110" rx="8" fill="#3e1e1e" stroke="#ef5350" stroke-width="1"/>
<text x="350" y="80" fill="#ef5350" font-size="15" font-weight="bold" text-anchor="middle">Software del Fabricante</text>
<text x="350" y="105" fill="#ccc" font-size="14" text-anchor="middle">ZKBioAccess, ADMS</text>
<text x="350" y="125" fill="#ccc" font-size="14" text-anchor="middle">Solo Windows, sin API</text>
<text x="350" y="145" fill="#ef5350" font-size="14" text-anchor="middle">❌ Sin integración cloud</text>
<rect x="475" y="55" width="195" height="110" rx="8" fill="#3e1e1e" stroke="#ef5350" stroke-width="1"/>
<text x="572" y="80" fill="#ef5350" font-size="15" font-weight="bold" text-anchor="middle">Competidores</text>
<text x="572" y="105" fill="#ccc" font-size="14" text-anchor="middle">CAMS, eSSL, MinopCloud</text>
<text x="572" y="125" fill="#ccc" font-size="14" text-anchor="middle">Precios opacos, docs malos</text>
<text x="572" y="145" fill="#ef5350" font-size="14" text-anchor="middle">❌ No es dev-friendly</text>
<rect x="30" y="195" width="640" height="85" rx="8" fill="#1b3a2d" stroke="#81c784" stroke-width="2"/>
<text x="350" y="220" fill="#81c784" font-size="17" font-weight="bold" text-anchor="middle">Así Que Lo Construimos Nosotros</text>
<text x="350" y="245" fill="#ccc" font-size="14" text-anchor="middle">4 meses de ingeniería → motor de protocolo → probado con 24,000+ empleados</text>
<text x="350" y="267" fill="#ccc" font-size="14" text-anchor="middle">Entonces nos dimos cuenta: si nosotros teníamos este problema, todos lo tienen</text>
</svg>

De Un Cliente a una Plataforma

Después de 6 meses en producción con AgriWise, seguíamos escuchando la misma pregunta: "¿Cómo conectan los dispositivos ZKTeco al cloud?"

No construimos un demo. Abrimos nuestro sistema de producción. El mismo motor que maneja los 24,000+ empleados de AgriWise alimenta cada llamada API de PunchConnect.

<svg viewBox="0 0 700 250" xmlns="http://www.w3.org/2000/svg" style="max-width:700px;width:100%;font-family:system-ui,sans-serif">
<rect width="700" height="250" fill="#1a1a2e" rx="12"/>
<text x="350" y="30" fill="#e0e0e0" font-size="17" font-weight="bold" text-anchor="middle">Herramienta Interna → Producto API</text>
<rect x="30" y="55" width="300" height="170" rx="8" fill="#2d2d44" stroke="#444" stroke-width="1"/>
<text x="180" y="80" fill="#4fc3f7" font-size="15" font-weight="bold" text-anchor="middle">Herramienta Interna</text>
<text x="180" y="105" fill="#ccc" font-size="14" text-anchor="middle">• Inquilino único</text>
<text x="180" y="125" fill="#ccc" font-size="14" text-anchor="middle">• Config hardcodeada</text>
<text x="180" y="145" fill="#ccc" font-size="14" text-anchor="middle">• Acceso directo a BD</text>
<text x="180" y="165" fill="#ccc" font-size="14" text-anchor="middle">• Monitoreo interno</text>
<text x="180" y="185" fill="#ccc" font-size="14" text-anchor="middle">• Sin docs necesarios</text>
<text x="180" y="210" fill="#81c784" font-size="14" text-anchor="middle">Funcionaba para nosotros ✓</text>
<text x="350" y="145" fill="#ff9800" font-size="34" text-anchor="middle">→</text>
<rect x="370" y="55" width="300" height="170" rx="8" fill="#1a3a5c" stroke="#4fc3f7" stroke-width="2"/>
<text x="520" y="80" fill="#4fc3f7" font-size="15" font-weight="bold" text-anchor="middle">Producto API (PunchConnect)</text>
<text x="520" y="105" fill="#ccc" font-size="14" text-anchor="middle">• Aislamiento multi-inquilino</text>
<text x="520" y="125" fill="#ccc" font-size="14" text-anchor="middle">• Gestión de API keys</text>
<text x="520" y="145" fill="#ccc" font-size="14" text-anchor="middle">• API REST + Webhooks</text>
<text x="520" y="165" fill="#ccc" font-size="14" text-anchor="middle">• Rate limiting por dispositivo</text>
<text x="520" y="185" fill="#ccc" font-size="14" text-anchor="middle">• Documentación completa</text>
<text x="520" y="210" fill="#81c784" font-size="14" text-anchor="middle">Funciona para todos ✓</text>
</svg>

Las Decisiones de Ingeniería Clave

1. Multi-Inquilino con Aislamiento por Dispositivo

python
@app.route("/v1/devices", methods=["GET"])
@require_api_key
def listar_dispositivos():
tenant_id = request.auth.tenant_id
dispositivos = db.query(
"SELECT * FROM devices WHERE tenant_id = %s", [tenant_id]
)
return jsonify({"devices": dispositivos})

2. Diseño de API: Lecciones de Stripe

- Formato de respuesta consistente en cada endpoint
- Códigos de error claros con identificadores específicos
- Claves de idempotencia en cada operación mutativa

3. Sistema de Entrega Webhook con Reintentos

python
RETRASOS_RETRY = [10, 60, 300, 1800, 7200] # segundos
def entregar_webhook(url: str, payload: dict, secreto: str):
body = json.dumps(payload)
firma = hmac.new(
secreto.encode(), body.encode(), hashlib.sha256
).hexdigest()
for intento, retraso in enumerate(RETRASOS_RETRY):
try:
resp = requests.post(url, data=body, headers={
"Content-Type": "application/json",
"X-PunchConnect-Signature": firma,
}, timeout=10)
if resp.status_code < 300:
return True
except requests.RequestException:
pass
time.sleep(retraso)
return False

4. La Documentación Como Producto

Para una herramienta interna, la documentación es una wiki que nadie lee. Para un producto API, la documentación ES el producto.

En México, esta solución cumple con la NOM-035-STPS. En Colombia, facilita el cumplimiento del Art. 161 del CST para control de jornada laboral.

Lo Que Aprendimos

| Métrica | Interno (AgriWise) | Producto (PunchConnect) |
|---------|-------------------|----------------------|
| Dispositivos | 80+ | En crecimiento |
| Empleados | 24,000+ | Variable por cliente |
| Disponibilidad | 99.7% | 99.7% (mismo motor) |
| Latencia webhook | 340ms prom. | 340ms prom. |
| Registros perdidos | Cero | Cero |
| Tiempo a primera integración | 4 meses | Menos de 5 minutos |

FAQ

¿PunchConnect sigue siendo usado internamente por AgriWise?

Sí. AgriWise funciona exactamente sobre el mismo motor. Las pruebas en producción nunca paran.

¿Cuánto toma integrar PunchConnect?

La mayoría de desarrolladores reciben su primer webhook en 5 minutos.

¿Qué dispositivos soporta PunchConnect?

Dispositivos biométricos ZKTeco — la marca más desplegada globalmente. SpeedFace, ProFace, UA860, K40, MB460 y la mayoría de modelos con conectividad de red.

¿En qué se diferencia de bibliotecas open-source como pyzk?

Las bibliotecas como pyzk se conectan por LAN — un dispositivo a la vez. PunchConnect es un servicio cloud: los dispositivos se conectan de salida, funcionan en cualquier red, manejan buffering offline y entregan datos vía webhooks.

¿Puedo probarlo antes de comprometerme?

Sí. Prueba gratis de 7 días con acceso completo a la API, sin tarjeta de crédito.

---

Prueba PunchConnect gratis por 7 días — de cero al primer webhook en menos de 5 minutos.

Artículos relacionados

De Herramienta Interna a Producto API: La Historia de PunchConnect | PunchConnect