Usar la API
En corto
Todo /public/v1 usa cursor para paginar, Idempotency-Key para no duplicar
una venta o un contacto, y devuelve 429 con Retry-After si te pasas de 120
lecturas o 30 escrituras por minuto. El dinero siempre va en _usd/_ves
como texto, nunca como número.
Base URL
Sección titulada «Base URL»https://api.wink-pos.com/public/v1
Paginación por cursor
Sección titulada «Paginación por cursor»Todas las listas usan un cursor opaco: ?limit= (1 a 100, 50 por defecto) y ?cursor=.
{ "data": [/* ... */], "nextCursor": "eyJvZmZzZXQiOjUwfQ" }- Sin
cursor: empieza en la primera página. nextCursor: null: no hay más páginas.- Un cursor inválido o de otra instalación responde 400
invalid_cursor: nunca vuelve en silencio al principio. Si tu sincronización guarda un cursor viejo, tienes que enterarte, no repetir el mismo tramo para siempre.
Sincronización incremental
Sección titulada «Sincronización incremental»Productos, ubicaciones, categorías, existencias, ventas y contactos aceptan ?updatedSince= (fecha ISO 8601). No está disponible en listas de precios.
Una fila que cambia durante el recorrido puede aparecer dos veces en la misma pasada (nunca se pierde): deduplica siempre por id.
Usa el mismo updatedSince en todas las páginas de un recorrido: el nextCursor que recibes con updatedSince solo sirve con updatedSince y en ese mismo recurso. Si lo mandas sin él, o a otro recurso, responde 400 invalid_cursor. Ante ese 400, vuelve a empezar el recorrido desde tu último updatedSince: es seguro, porque deduplicas por id.
Escrituras idempotentes
Sección titulada «Escrituras idempotentes»Todo POST que crea un documento exige el encabezado Idempotency-Key:
POST /public/v1/salesIdempotency-Key: 8f2c4e10-3b7a-4e2a-9b1a-6a7c4e1a2b3c- Sin el encabezado: 400
idempotency_key_required. - Clave repetida, mismo cuerpo: 200 con el documento que ya existía (no 201: no crea uno nuevo).
- Clave repetida, cuerpo distinto: 422
idempotency_key_reused. La comparación es aproximada (ubicación, canal, cliente y líneas/cobros en el mismo orden), no un hash exacto del JSON. - Usa un id estable de tu lado como clave: por ejemplo, el id del pedido en tu sistema. Reenviar la misma clave ante un timeout o un reintento de red siempre es seguro.
- Un
PATCHno necesitaIdempotency-Key: aplicarlo dos veces deja el recurso en el mismo estado.
Límites de peticiones
Sección titulada «Límites de peticiones»| Cupo | Límite |
|---|---|
Lectura (GET) |
120 por minuto por instalación |
| Escritura (el resto de métodos) | 30 por minuto por instalación |
Pasado el límite: 429 rate_limited, con Retry-After, RateLimit-Limit y RateLimit-Remaining del cupo que tocaste. Respeta Retry-After antes de reintentar.
Forma de los errores
Sección titulada «Forma de los errores»{ "error": { "code": "insufficient_scope", "message": "Falta el permiso catalog.view", "details": [{ "field": "scope", "issue": "catalog.view" }] }}details solo aparece en errores de validación, con el campo exacto que falló. La lista completa de códigos estables está en Referencia › Errores.
Fechas y dinero
Sección titulada «Fechas y dinero»- Fechas en ISO 8601, UTC.
- Montos en dos monedas, siempre como string decimal, nunca número:
amountUsdyamountVes, másexchangeRatecuando aplica. No los parsees comofloat: usa una librería decimal de tu lenguaje para sumarlos o compararlos.
Versión y política de cambios
Sección titulada «Versión y política de cambios»Vives en v1. Dentro de v1 solo hay cambios compatibles: campos nuevos opcionales y endpoints nuevos. Un cambio que rompe algo existente sale como v2, con al menos 6 meses de convivencia con v1. Revisa Cambios para el historial de cada versión del contrato.