Inventario externo
Con esta integración, el sistema de inventario del negocio (producción, bodega, compras) es la fuente de verdad de la existencia. papedir la muestra en su punto de venta y su tienda en línea, sigue descontando cada venta al instante y te avisa de cada pedido para que lo registres.
Tu sistema ──PUT /stock (absoluto)──▶ papedir ▲ │ └──── webhook order.created ─────────┘ (o GET /orders + ack)Base: https://api.pedidos.transformit.com.co/api/v1/external. Autenticación y scopes en
conceptos; errores en errores.
GET /catalog?cursor=&limit= (scope catalog:read)
Sección titulada «GET /catalog?cursor=&limit= (scope catalog:read)»Devuelve los productos vivos del negocio en orden de id, entre 1 y 500 por página (100 por
defecto). Para pedir la siguiente página se pasa next_cursor como cursor; cuando es null, no
hay más.
{"items":[{"id":43,"sku":"PAN-01","external_id":"b3f…","name":"Pan de yuca","unit":"unidad", "stock":12,"tracked":true,"available":true,"updated_at":"2026-10-08T15:00:00Z"}], "next_cursor":43}tracked: false significa que papedir no lleva inventario de ese producto: la existencia que se le
mande se ignora (untracked). El negocio decide qué productos llevan inventario.
PATCH /catalog/mapping (scope stock:write)
Sección titulada «PATCH /catalog/mapping (scope stock:write)»Hace el cruce inicial: le asigna a cada producto de papedir, buscado por su SKU, el id que tiene en
tu sistema. Con null se quita el cruce. Acepta hasta 500 productos por petición.
curl -s -X PATCH "$BASE/catalog/mapping" -H "Authorization: Bearer $LLAVE" \ -H 'Content-Type: application/json' \ -d '{"items":[{"sku":"PAN-01","external_id":"b3f1c2d4-…"},{"sku":"PAN-02","external_id":null}]}'# {"results":[{"index":0,"sku":"PAN-01","status":"mapped","menu_item_id":43},# {"index":1,"sku":"PAN-02","status":"unmapped","menu_item_id":44}]}- Resultado por producto:
mapped: quedó cruzado.unmapped: se quitó el cruce.not_found: no hay producto con ese SKU.conflict: eseexternal_idya lo tiene otro producto del negocio.
- Regla del
external_id: es único por negocio y no distingue mayúsculas.
PUT /stock (scope stock:write)
Sección titulada «PUT /stock (scope stock:write)»Envía la existencia absoluta, no un delta, de hasta 500 productos por petición.
- Cabecera obligatoria
Idempotency-Key: de 8 a 100 caracteres (letras, números,. _ : -), única por lote. En un reintento se repite la misma: papedir no vuelve a aplicar lo que ya aplicó. - Cada ítem trae:
external_idosku. Si vienen los dos, ganaexternal_id.stock: un número entre 0 y 99.999.999.999,999, con hasta 3 decimales.- Opcional,
version: un entero que crece con cada cambio en tu sistema (un contador oupdated_aten milisegundos). - Opcional,
observed_at: una fecha ISO 8601; sirve cuando no hay versión.
- Lo que llega tarde se descarta: si llega una versión o fecha menor o igual a la última
aplicada, el ítem sale
stale. Así no importa el orden en que lleguen los envíos.
curl -s -X PUT "$BASE/stock" -H "Authorization: Bearer $LLAVE" \ -H 'Idempotency-Key: lote-2026-10-08T15:00:00Z' -H 'Content-Type: application/json' \ -d '{"items":[{"external_id":"b3f1c2d4-…","stock":12,"version":1728399600000}, {"sku":"PAN-02","stock":7.5}]}'{"results":[ {"index":0,"external_id":"b3f1c2d4-…","sku":null,"menu_item_id":43,"status":"applied","stock_after":12}, {"index":1,"external_id":null,"sku":"PAN-02","menu_item_id":44,"status":"applied","stock_after":7.5}], "summary":{"applied":2,"duplicate":0,"stale":0,"not_found":0,"untracked":0,"invalid":0}}status | Qué pasó | Qué hacer |
|---|---|---|
applied | La existencia quedó en stock | — |
duplicate | Ese lote ya se había aplicado (misma Idempotency-Key) | Nada: es un reintento |
stale | Llegó una versión o fecha más vieja que la última aplicada | Nada, o mandar la versión actual |
not_found | No hay producto vivo con ese external_id o sku | Hacer el cruce, o revisar si se borró |
untracked | El producto no lleva inventario en papedir | Pedirle al negocio que lo active |
invalid | Ítem mal formado, o el mismo producto repetido en el lote | Mandar un solo ítem por producto |
- Resultados en orden: la respuesta trae un resultado por ítem, en el orden en que se mandaron.
- Un ítem malo no tumba el lote: los demás se aplican igual.
- Rechazo del lote entero: solo pasa con 400, cuando el cuerpo no cumple el formato
(
VALIDATION_FAILED;error.detailsdice qué campo falla) o cuando falta laIdempotency-Key.
Pedidos
Sección titulada «Pedidos»Cada pedido genera order.created, order.updated u order.cancelled. Recíbelos por
webhook o léelos del feed GET /orders y confírmalos con POST /orders/ack
(detalle en la referencia).
Cómo conviven las ventas
Sección titulada «Cómo conviven las ventas»- papedir sigue descontando cada pedido al crearlo. No deja vender lo que no hay entre dos envíos tuyos.
- Tu sistema recibe el
order.created, registra la venta y vuelve a mandar la existencia. - Reservas pendientes: mientras tu sistema no confirme un
order.created(con 2xx del webhook o conack), papedir resta esa venta a la existencia absoluta que mandes. El resultado de cada ítem traereserved. Así un envío tuyo que todavía no incluye la venta no hace que papedir vuelva a vender lo que ya vendió.- La reserva dura como máximo 48 horas, o hasta que el evento queda
dead(8 intentos fallidos). Después deja de restarse.
- La reserva dura como máximo 48 horas, o hasta que el evento queda
- Confirma antes de mandar la existencia: responde 2xx (o haz
ack) antes de enviar la existencia que ya incluye la venta. Si la mandas antes, papedir la resta dos veces hasta tu siguiente envío. - Cancelación: con
order.cancelled, devuelve la existencia en tu sistema y mándala.
Recomendaciones
Sección titulada «Recomendaciones»- Primera vez:
GET /catalog.- Cruzar por SKU con
PATCH /catalog/mapping. - Un
PUT /stockcon todo.
- Después: mandar solo lo que cambió, con
version, y un envío completo al día como conciliación. - Reintentos: con la misma
Idempotency-Keyy espera exponencial ante 429 o 5xx. Un 4xx distinto de 429 no se reintenta sin corregir la petición.