Documentación.
API REST para consultar tracking, agencias y ubicaciones de shalom.com.pe, y crear pedidos en pro.shalom.pe.
Auth
X-API-Key
Rate limit
60 / min
Formato
JSON
Base URL: https://api.shalom-api-peru.com
Quickstart
De cero a tu primera guía creada y rastreada, en cuatro llamadas. Cada paso usa lo que devolvió el anterior. Necesitas dos cosas antes de empezar: tu API key (la pides por WhatsApp) y las credenciales de Shalom Pro del cliente — email y password de pro.shalom.pe.
Paso 1 — Cambia email y password por un token
Todo lo que toca la cuenta del cliente (productos, órdenes, tracking) pide credenciales de Shalom Pro. Las canjeas una vez por un session_token que dura 2 horas, y de ahí en adelante mandas solo el token.
Esta llamada es la lenta: tarda entre 90 s y 2 min porque Shalom hace un login real, así que pon el timeout de tu cliente en ≥ 150 s o te vas a estrellar aquí. Las siguientes salen rápido. Detalle en Autenticación.
curl -X POST https://api.shalom-api-peru.com/v1/shalom/sessions \
-H "X-API-Key: tu-api-key" \
-H "Content-Type: application/json" \
--max-time 150 \
-d '{
"email": "cliente@empresa.com",
"password": "tu-password-de-shalom-pro"
}'
Te devuelve { "session_token": "ssk_a1b2c3d4e5f6...", "expires_at": "..." }. Ese ssk_... va en el header X-Shalom-Session de todos los pasos siguientes.
Paso 2 — Consigue los tres ids que pide la orden
Para crear una guía necesitas la agencia de origen, la de destino y el tipo de paquete. Las agencias salen de /v1/agencies/search, que solo pide X-API-Key:
curl "https://api.shalom-api-peru.com/v1/agencies/search?q=arequipa" \
-H "X-API-Key: tu-api-key"
El id de cada agencia es lo que mandas como origin_terminal_id y destiny_terminal_id. En el ejemplo: 404 y 7. El tipo de paquete sale de /v1/products, y aquí sí reusas el token:
curl https://api.shalom-api-peru.com/v1/products \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Session: ssk_a1b2c3d4e5f6..."
Toma el id del producto — 3 es Sobre — y pásalo como product_id.
Paso 3 — Crea la guía
Junta los tres ids, el destinatario y una clave de retiro de 4 dígitos (pickup_code, ni repetida ni consecutiva). El remitente no se manda: Shalom lo toma de la cuenta del token (salvo que pidas una guía empresarial).
curl -X POST https://api.shalom-api-peru.com/v1/orders \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Session: ssk_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"origin_terminal_id": 404,
"destiny_terminal_id": 7,
"product_id": 3,
"quantity": 1,
"payer": "sender",
"declaracion_jurada": "docs",
"receiver": {
"document_type": "DNI",
"document": "87654321",
"name": "MARIA",
"last_name": "GOMEZ",
"sur_name": "TORRES",
"phone": 998765432
},
"pickup_code": "2415"
}'
Respuesta: { "guia": "80574902", "serie": "v872", "codigo": "CJTW", "ose_id": 584210 }. Guarda guia y codigo para rastrear, y el ose_id si vas a descargar el rótulo en PDF.
Esto crea una guía real y cobrable en la cuenta del cliente, visible en su panel. No hay sandbox y no hay idempotencia: si la llamada te da timeout, no la reintentes a ciegas — consulta primero GET /v1/orders para ver si la guía ya se creó, o la vas a duplicar. Si la creaste probando, bórrala con DELETE /v1/orders/{id} mientras no haya sido recibida en agencia.
Paso 4 — Rastréala
La guia del paso 3 va como numero, y el codigo tal cual. Mismo token del paso 1.
curl -H "X-API-Key: tu-api-key" \
-H "X-Shalom-Session: ssk_a1b2c3d4e5f6..." \
"https://api.shalom-api-peru.com/v1/tracking?numero=80574902&codigo=CJTW" Eso es la integración completa. Desde aquí: cotiza antes de crear, sube un lote por Excel, o rastrea hasta 50 guías de un tiro.
Autenticación
Hay dos niveles. El X-API-Key va en todas las rutas. Los endpoints que tocan la cuenta del cliente en Shalom Pro (tracking, órdenes, productos, personas, tarifas) exigen además sus credenciales. Agencias, ubicaciones y health solo necesitan la API key.
X-API-Key: tu-api-key Credenciales de Shalom Pro — dos opciones
| Opción | Headers | Cuándo |
|---|---|---|
| A — token efímero (recomendada) | X-Shalom-Session: ssk_... | Pides el token una vez con POST /v1/shalom/sessions y dura 2 h. El password viaja una sola vez. Tiene precedencia si mandas ambas. |
| B — directo | X-Shalom-Email X-Shalom-Password | Sin paso previo, pero el password viaja en cada llamada. Para scripts cortos y pruebas. |
El password no se loguea ni se persiste en nuestro servidor.
La primera llamada es lenta
La primera llamada de cada cuenta hace un login real contra Shalom y tarda ~90 s, hasta 2 min. Las siguientes son rápidas: la sesión queda caliente y se reutiliza. Configura el timeout de tu cliente en ≥ 150 s o la primera llamada se te cortará sola. Ver Latencia y reintentos.
Solicita tu API key por WhatsApp:
948 997 674Identificadores
Un envío tiene varios ids y no son intercambiables. Los dos que más se confunden: ose_id sirve para rastrear y descargar PDFs; id sirve para borrar la orden.
| Campo | Qué es | Dónde lo obtienes | Dónde lo usas |
|---|---|---|---|
| guia | 8–10 dígitos. Va impresa en el comprobante físico. | POST /v1/orders | GET /v1/tracking?numero= |
| codigo | Alfanumérico de 4 caracteres. Lo asigna Shalom. | POST /v1/orders | GET /v1/tracking?codigo= |
| ose_id | ID interno de Shalom del envío. No hace falta enviarlo para rastrear: te lo damos nosotros. | POST /v1/orders · order.ose_id del tracking | /events, /grt, /label, /voucher |
| id | ID de la orden dentro de la cuenta empresarial. | GET /v1/orders | DELETE /v1/orders/{id} |
| pickup_code | Clave de 4 dígitos para retirar en agencia. La eliges tú. | La defines al crear la orden | La presenta el destinatario en agencia |
| serie | Prefijo del talonario (ej. "v872"). | POST /v1/orders | Informativo. No se usa en esta API. |
| internal_id | ID interno del panel de Shalom Pro. | GET /v1/orders | Informativo. No se usa en esta API. |
GET/v1/tracking Busca una guía y retorna su estado, más la orden completa si autenticas. Tiene dos modos según qué mandes.
Modo estado (público). Con solo X-API-Key + numero, cualquier guía del sistema devuelve su línea de tiempo (status). No necesita credenciales Shalom. La respuesta trae detailed: false y omite order.
Modo detallado. Si además mandas credenciales Shalom (ver Autenticación), agregamos la orden completa (order: montos, fechas, contenido) y detailed: true. Si las credenciales fallan o Shalom rechaza la orden, la respuesta degrada al modo estado en vez de romper. Guía inexistente → 404.
Query params (al menos 1 requerido)
Param Tipo Descripción numero string 8 a 10 dígitos (ej. "12345678"). Es la guia. codigo string Alfanumérico de 4 caracteres (ej. "CJTW"). ose_id string ID interno de Shalom del envío. No lo consigues tú: lo devuelve POST /v1/orders y también viene en order.ose_id del rastreo.
Para el estado basta el numero (o el ose_id). El codigo por sí solo no resuelve el estado: úsalo junto al numero, o solo con credenciales Shalom. Ambos vienen impresos en el comprobante físico. Ver Identificadores.
Request — modo estado (solo API key) curl -H "X-API-Key: mi-key" \
"https://api.shalom-api-peru.com/v1/tracking?numero=82100156"
200 OK — modo estado (detailed: false) {
"detailed": false,
"status": {
"registrado": { "fecha": "2026-04-15 09:12:30" },
"origen": { "fecha": "2026-04-15 09:12:30" },
"transito": { "fecha": "2026-04-15 14:08:21", "completo": true,
"cargueros": ["964724", "966345"], "carguero": "966345" },
"demora": null,
"destino": { "fecha": "2026-04-16 01:01:03", "completo": true },
"entregado": { "fecha": "2026-04-16 11:40:45" },
"reparto": null
}
}
Request — modo detallado (numero + codigo + credenciales) curl -H "X-API-Key: mi-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
"https://api.shalom-api-peru.com/v1/tracking?numero=82100156&codigo=W79H"
Request — modo detallado por ose_id curl -H "X-API-Key: mi-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
"https://api.shalom-api-peru.com/v1/tracking?ose_id=584210"
200 OK — modo detallado (detailed: true) {
"detailed": true,
"order": {
"ose_id": 584210,
"numero_orden": "82100156",
"codigo_orden": "W79H",
"fecha_emision": "2026-04-14 09:12:30",
"fecha_traslado": "2026-04-15 09:12:30",
"tipo_pago": "Contra entrega",
"estado_pago": "CA",
"contenido": "1 MINI PAQUETERIA XS",
"monto": "10.00",
"entregado": true,
"reparto": false,
"aereo": false,
"tiempo_llegada": "",
"origen": { "id": 0, "nombre": "", "abrebiatura": "", "ubigeo": 0, "departamento": "", "provincia": "", "distrito": "" },
"destino": { "id": 0, "nombre": "", "abrebiatura": "", "ubigeo": 0, "departamento": "", "provincia": "", "distrito": "" },
"remitente": { "documento": "", "nombre": "" },
"destinatario": { "documento": "", "nombre": "" },
"comprobante": { "cop_id": 0, "serie": "", "numero": "", "tipo": "", "tipo_pago": "", "estado_pago": "", "fecha": "", "hora": "" }
},
"status": {
"registrado": { "fecha": "2026-04-15 09:12:30" },
"origen": { "fecha": "2026-04-15 09:12:30" },
"transito": { "fecha": "2026-04-15 14:08:21", "completo": true,
"cargueros": ["964724", "964583", "966345"], "carguero": "966345" },
"demora": null,
"destino": { "fecha": "2026-04-16 01:01:03", "completo": true },
"entregado": { "fecha": "2026-04-16 11:40:45" },
"reparto": null
}
}
El campo detailed te dice qué esperar. Cuando es false (modo estado) la respuesta trae solo status y omite order. Cuando es true aparece order, pero sus bloques origen, destino, remitente, destinatario y comprobante llegan vacíos: desde julio de 2026 Shalom dejó de incluirlos en su respuesta de rastreo, y los devolvemos en cero para no romper el shape de quienes ya los leen. No construyas sobre esos campos. De order lo que sí llega: los identificadores, las fechas, contenido, monto, tipo_pago, estado_pago y los flags (entregado, reparto, aereo). El objeto status completo llega en ambos modos.
Los hitos de status
status trae los siete hitos del envío. Los que todavía no ocurrieron llegan en null — es lo normal en un envío en curso, no un error.
Hito Descripción registrado La orden se registró en el sistema. origen Recibido en la agencia de origen. transito En viaje. Único hito que trae cargueros[] (todos los transportistas que movieron el envío) y carguero (el último). Esos ids son el cap_id que pide el GRT. demora Incidencia que retrasó el envío. Normalmente null. destino Llegó a la agencia de destino. entregado Entregado al destinatario. reparto Salió a reparto a domicilio. null si la entrega es en agencia.
La fecha incluye la hora. Cada hito trae un solo campo fecha con formato "YYYY-MM-DD HH:MM:SS" — no hay un campo hora separado.
POST/v1/tracking/batch
Rastrea varias guías en una sola llamada (hasta 50 por request). Cada item usa los mismos identificadores que GET /v1/tracking (numero, codigo u ose_id — al menos uno) más un custom_id opcional. Ideal para refrescar el estado de muchos envíos sin hacer N requests.
Body
Campo Tipo Descripción items[] array Lista de guías a rastrear. Requerido, de 1 a 50 elementos. items[].custom_id string Etiqueta libre tuya (ej. tu id de pedido). No la interpretamos: la devolvemos verbatim en el resultado para que correlaciones cada respuesta con tu sistema. Opcional. items[].numero / codigo / ose_id string Identificadores de la guía. Al menos uno por item, igual que en GET /v1/tracking.
Errores por item, no por batch. Un item que falla (guía inexistente, sin identificador, etc.) no tumba al resto: ese item trae ok: false con su error (mismo code que daría GET /v1/tracking), y el status global sigue siendo 200. Solo devuelve 400 si el envelope está malformado (JSON inválido, items vacío, o más de 50).
Orden preservado. results sale en el mismo orden que mandaste items, y cada resultado hace echo de custom_id y de los identificadores enviados — puedes correlacionar por posición o por custom_id.
Request curl -X POST https://api.shalom-api-peru.com/v1/tracking/batch \
-H "X-API-Key: mi-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "custom_id": "pedido-001", "numero": "82100156", "codigo": "W79H" },
{ "custom_id": "pedido-002", "ose_id": "584210" },
{ "custom_id": "pedido-003", "numero": "00000000" }
]
}'
200 OK — order y status recortados por brevedad {
"results": [
{
"custom_id": "pedido-001",
"numero": "82100156",
"codigo": "W79H",
"ok": true,
"tracking": {
"detailed": true,
"order": { "ose_id": 584210, "numero_orden": "82100156", "entregado": true },
"status": { "entregado": { "fecha": "2026-04-16 11:40:45" } }
}
},
{
"custom_id": "pedido-002",
"ose_id": "584210",
"ok": true,
"tracking": {
"detailed": false,
"status": { "entregado": { "fecha": "2026-04-16 11:40:45" } }
}
},
{
"custom_id": "pedido-003",
"numero": "00000000",
"ok": false,
"error": { "code": "not_found", "message": "orden no existe" }
}
],
"summary": { "total": 3, "ok": 2, "failed": 1 }
}
Campos de la respuesta
Campo Tipo Descripción results[].ok bool true si la guía se rastreó; false si falló. results[].tracking object Presente cuando ok: true. Mismo shape que la respuesta de GET /v1/tracking (order + status). results[].error object Presente cuando ok: false. { code, message }, con el mismo code que devolvería el tracking individual. summary object { total, ok, failed } — conteos del batch.
GET/v1/tracking/{ose_id}/events Solo los hitos del envío: registrado, origen, tránsito, demora, destino, entregado, reparto. Es el mismo objeto status que ya trae GET /v1/tracking — úsalo cuando solo necesitas refrescar el estado y ya tienes el ose_id.
Path Tipo Descripción ose_id string ID del sistema OSE (SUNAT) — el campo order.ose_id de la respuesta de GET /v1/tracking. Es el handle público para acceder a eventos, comprobante y GRT.
200 OK {
"registrado": { "fecha": "2026-04-15 09:12:30" },
"origen": { "fecha": "2026-04-15 09:12:30" },
"transito": { "fecha": "2026-04-15 14:08:21", "completo": true,
"cargueros": ["964724", "964583", "966345"], "carguero": "966345" },
"demora": null,
"destino": { "fecha": "2026-04-16 01:01:03", "completo": true },
"entregado": { "fecha": "2026-04-16 11:40:45" },
"reparto": null
}
GET/v1/tracking/{ose_id}/voucher Comprobante de la orden.
Fuera de servicio temporalmente. Hoy este endpoint responde 404 not_found para cualquier orden. El comprobante se localiza con datos que Shalom dejó de enviar en su respuesta de rastreo (ver el aviso en GET /v1/tracking), así que no hay forma de resolverlo. Estamos migrando a la nueva ruta de comprobantes de Shalom; mientras tanto, no dependas de este endpoint.
GET/v1/tracking/{ose_id}/grt?cap_id={cap_id} Enlace a la Guía de Remisión del Transportista. Un envío puede pasar por varios cargueros (transportistas) y cada uno emite su propio GRT — por eso el cap_id es obligatorio.
Param En Descripción ose_id path ID del sistema OSE (SUNAT) — el campo order.ose_id de la respuesta de GET /v1/tracking. cap_id query ID del carguero (transportista). Los ids están en status.transito.cargueros[] de GET /v1/tracking. (requerido)
Request curl -H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
"https://api.shalom-api-peru.com/v1/tracking/584210/grt?cap_id=898441"
200 OK {
"enlace": "https://..."
}
GET/v1/agencies Lista paginada de agencias.
Param Default Descripción page 1 Página per_page 100 Ítems por página (máx 500)
200 OK {
"page": 1,
"per_page": 100,
"items": [
{
"id": 1,
"nombre": "LIMA CENTRO",
"departamento": "LIMA",
"aereo": true,
"latitud": -12.046,
"longitud": -77.030
}
]
}
GET/v1/agencies/search Busca por texto o por filtros de ubicación.
Param Tipo Descripción q string Texto libre departamento string Filtrar por departamento provincia string Filtrar por provincia aereo bool Servicio aéreo
GET/v1/agencies/{id} Detalle completo de una agencia por ID numérico.
GET/v1/locations/departments Todos los departamentos del Perú.
{
"items": [
{ "id": 1, "name": "AMAZONAS", "ubi_id": 101 }
]
}
GET/v1/locations/departments/{depId}/provinces Provincias de un departamento.
Path Descripción depId ID del departamento
GET/v1/locations/departments/{depId}/provinces/{provId}/districts Distritos de una provincia.
Path Descripción depId ID del departamento provId ID de la provincia
Crear pedido en Shalom Pro
Crea una guía de envío real en la cuenta de Shalom Pro del cliente y devuelve los identificadores para tracking, descarga de PDF y operaciones posteriores. La resolución de remitente y destinatario, la validación del servicio de cobranza y la cotización se hacen automáticamente en una sola llamada.
Cada POST /v1/orders exitoso crea una preguía real en la cuenta de Shalom Pro, visible en el panel de pro.shalom.pe. Si la creaste por error, bórrala con DELETE /v1/orders/{id} mientras no haya sido despachada.
Estos endpoints necesitan X-API-Key + credenciales de Shalom Pro: ver Autenticación.
Latencia y reintentos
La primera llamada de cada cuenta hace un login real contra Shalom y tarda ~90 s, hasta 2 min. Las siguientes son rápidas: la sesión queda caliente y se reutiliza. Aplica a crear pedido, tracking, sesiones, bulk y productos.
Configura el timeout de tu cliente HTTP en al menos 150 s para estos endpoints. Con un timeout corto (20–30 s) la primera llamada se corta antes de terminar y te devuelve un error aunque la operación siga en curso del lado del servidor.
Si una llamada se corta por timeout
En las lecturas (tracking, productos, tarifa, listar órdenes, crear sesión) reintenta sin miedo: la sesión termina de calentarse en segundo plano y el reintento sale rápido.
No reintentes a ciegas POST /v1/orders ni /v1/orders/bulk. Un timeout de tu cliente no significa que la orden no se creó: puede haberse creado igual. Como la API no tiene clave de idempotencia, un reintento crearía una segunda guía real y cobrable. Ante un timeout al crear, consulta primero GET /v1/orders y revisa si la guía ya está ahí; reintenta solo si no aparece.
Usar la opción A concentra el arranque lento en una sola llamada: pides el token con POST /v1/shalom/sessions (una lectura, reintentable sin riesgo) y las órdenes posteriores ya salen rápidas.
POST/v1/shalom/sessions
Valida las credenciales contra pro.shalom.pe y emite un token efímero (formato ssk_<64-hex>) con TTL de 2 horas.
El password viaja en el body (no en headers, que suelen acabar en logs) y no se persiste: se usa para emitir el token y se descarta.
Request curl -X POST https://api.shalom-api-peru.com/v1/shalom/sessions \
-H "X-API-Key: tu-api-key" \
-H "Content-Type: application/json" \
-d '{
"email": "cliente@empresa.com",
"password": "tu-password-de-shalom-pro"
}'
200 OK {
"session_token": "ssk_a1b2c3d4e5f6...",
"expires_at": "2026-05-08T18:23:01Z"
}
Body
Campo Tipo Descripción email string Email de la cuenta en pro.shalom.pe. password string Password de esa cuenta.
Cuándo expira el token
Dura 2 horas desde su emisión. Un token vencido devuelve 401 shalom_auth_failed: pide uno nuevo. Los tokens viven en memoria, así que un reinicio del servicio los invalida.
DELETE/v1/shalom/sessions
Revoca un token antes de que expire. Idempotente: si el token ya estaba revocado o nunca existió, igual responde 200. Útil para forzar logout cuando el cliente cambia de cuenta o detecta actividad sospechosa.
Request curl -X DELETE https://api.shalom-api-peru.com/v1/shalom/sessions \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Session: ssk_a1b2c3d4e5f6..."
200 OK { "revoked": true }
El token a revocar va en el header X-Shalom-Session, no en el path ni en el body. Si el header falta, devuelve 400.
GET/v1/products
Lista los productos disponibles en la cuenta de Shalom Pro del cliente: Sobre, Caja Paquete XXS/XS/S/M/L y Otra Medida. Devuelve el id que usas en el body de POST /v1/orders y las dimensiones default de cada uno.
Mismo auth Shalom que el resto (ver Autenticación). La conexión con Shalom se reutiliza entre todos los endpoints: si ya creaste una orden con esas credenciales, esta llamada no vuelve a pagar el login.
Request curl https://api.shalom-api-peru.com/v1/products \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro"
200 OK {
"products": [
{
"id": 3,
"title": "Sobre",
"img": "https://pro.shalom.pe/img/products/sobre.png",
"content": "Hasta 0.5 kg",
"sub_content": "Documentos y similares",
"measurements": {
"weight": 0.5,
"width": 0.3,
"height": 0.02,
"length": 0.4
}
},
{
"id": 1098,
"title": "Otra Medida",
"img": "https://pro.shalom.pe/img/products/custom.png",
"content": "Define las dimensiones",
"sub_content": "Para bultos fuera de catálogo",
"measurements": { "weight": 0, "width": 0, "height": 0, "length": 0 }
}
]
}
Campos del producto
Campo Tipo Descripción id int ID del producto. Pásalo en product_id al crear la orden. title string Nombre legible: "Sobre", "Caja Paquete XS", "Otra Medida", etc. content string Descripción corta del límite de peso. sub_content string Texto auxiliar: ejemplos de uso. img string URL del thumbnail para mostrar en tu UI. measurements object Medidas default { weight, width, height, length } en kg/m. Para Otra Medida vienen en cero — defínelas tú en el body de la orden.
Otra Medida — bulto fuera de catálogo
Si tu envío no entra en los tamaños estándar, usa el producto cuyo title sea "Otra Medida" y manda el campo opcional dimensions en el body de POST /v1/orders con { weight_kg, height_m, length_m, width_m }. Para los demás productos puedes omitirlo y se usan las medidas default.
GET/v1/persons/search?document={document}&type={type}
Resuelve un documento (DNI/RUC/CE) a una persona registrada en pro.shalom.pe. Útil para autocomplete en formularios — el usuario tipea su DNI y tú pre-cargas nombre, apellidos y teléfono antes del submit.
No es obligatorio antes de crear una orden. POST /v1/orders ya resuelve la persona automáticamente cuando le pasas el documento. Este endpoint sirve cuando quieres mostrar los datos al usuario antes del submit, o conseguir el id para reusarlo en envíos siguientes.
Request curl "https://api.shalom-api-peru.com/v1/persons/search?document=70123456&type=DNI" \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro"
200 OK {
"id": 1234567,
"document_type": "DNI",
"document": "70123456",
"name": "JUANA",
"last_name": "RAMOS",
"sur_name": "LOPEZ",
"full_name": "JUANA RAMOS LOPEZ",
"phone": 999111222,
"email": null,
"address": null
}
Query params
Param Tipo Descripción document string Documento a buscar (8 dígitos para DNI, 11 para RUC, alfanumérico ≥4 para CE) (requerido) type string "DNI", "RUC" o "CE" (case-insensitive) (requerido)
Errores específicos
HTTP code Cuándo se da 400 bad_request Falta document o type, type fuera de DNI/RUC/CE, o longitud inválida (DNI≠8, RUC≠11, etc.) 404 not_found El DNI/RUC/CE no figura en Shalom Pro.
404 — persona no encontrada {
"error": {
"code": "not_found",
"message": "persona no registrada en Shalom Pro",
"request_id": "01KS..."
}
}
POST/v1/tariff/calculate
Calcula el precio de un envío entre dos terminales sin comprometer la orden. Devuelve el precio para cada tipo de producto del catálogo (sobre, cajas XXS/XS/S/M/L y otra medida) para que puedas mostrar la cotización antes del checkout.
Request curl -X POST https://api.shalom-api-peru.com/v1/tariff/calculate \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
-H "Content-Type: application/json" \
-d '{
"origin_terminal_id": 66,
"destiny_terminal_id": 7,
"dimensions": {
"weight_kg": 1.0,
"height_m": 0.1,
"length_m": 0.2,
"width_m": 0.15
}
}'
200 OK {
"currency": "PEN",
"breakdown": {
"sobre": 8.00,
"caja_paquete_xxs": 8.00,
"caja_paquete_xs": 10.00,
"caja_paquete_s": 12.00,
"caja_paquete_m": 15.00,
"caja_paquete_l": 20.00,
"otra_medida": 25.00
}
}
Body
Campo Tipo Descripción origin_terminal_id integer ID del terminal de origen (lo obtienes de /v1/agencies) (requerido) destiny_terminal_id integer ID del terminal de destino (requerido) dimensions object Peso y medidas del paquete (weight_kg, height_m, length_m, width_m). Afectan SOLO el precio de otra_medida. Si no se pasan, se usan defaults mínimos. product_id integer Si lo pasas, la respuesta incluye un campo product con el precio puntual para mostrar al usuario. Si el id no existe en el catálogo, el campo se omite (la respuesta sigue siendo 200 con el breakdown).
Con product_id — precio puntual
Si ya sabes qué producto va a comprar el usuario, manda product_id y te ahorras el mapeo manual del breakdown:
Request curl -X POST https://api.shalom-api-peru.com/v1/tariff/calculate \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
-H "Content-Type: application/json" \
-d '{
"origin_terminal_id": 66,
"destiny_terminal_id": 7,
"product_id": 3
}'
200 OK {
"currency": "PEN",
"breakdown": {
"sobre": 8.00,
"caja_paquete_xxs": 8.00,
"caja_paquete_xs": 10.00,
"caja_paquete_s": 12.00,
"caja_paquete_m": 15.00,
"caja_paquete_l": 20.00,
"otra_medida": 25.00
},
"product": {
"id": 3,
"title": "Sobre",
"price": 8.00
}
}
Errores: los generales. El 400 se da si faltan origin_terminal_id o destiny_terminal_id.
POST/v1/orders Crea una guía de envío. Devuelve guia, serie y codigo — los identificadores con los que después puedes trackear o borrar la orden.
Request curl -X POST https://api.shalom-api-peru.com/v1/orders \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
-H "Content-Type: application/json" \
-d '{
"origin_terminal_id": 404,
"destiny_terminal_id": 7,
"product_id": 3,
"quantity": 1,
"payer": "sender",
"declaracion_jurada": "docs",
"receiver": {
"document_type": "DNI",
"document": "87654321",
"name": "MARIA",
"last_name": "GOMEZ",
"sur_name": "TORRES",
"phone": 998765432
},
"pickup_code": "2415"
}'
200 OK {
"guia": "80574902",
"serie": "v872",
"codigo": "CJTW",
"ose_id": 584210
}
Guarda el ose_id: lo necesitas para descargar el rótulo y el comprobante. Qué es cada identificador de la respuesta, en Identificadores.
Todos los campos del body — requeridos y opcionales — están en Campos del body. Ojo con declaracion_jurada: es requerido ("docs", "ropa", "art" o "electro"); si lo omites, la API responde 400.
Errores propios de crear pedido
HTTP code Cuándo se da 409 conflict Ya hay una persona registrada con ese documento: pasa su id en vez de los datos. 422 upstream_rejected Regla de negocio de Shalom: cuenta sin servicio de cobranza, producto restringido para esa ruta, etc.
El resto, en Errores.
401 — credenciales rechazadas {
"error": {
"code": "shalom_auth_failed",
"message": "X-Shalom-Email/Password rechazados por Shalom Pro",
"request_id": "01KQ..."
}
}
POST/v1/orders/bulk
Carga masiva de envíos desde la plantilla Excel de Shalom Pro (Formato-Pro-Masivo.xlsx). El wrapper importa el archivo, lo valida (todo-o-nada), asigna la misma clave de retiro a todo el lote y lo emite — en una sola llamada. Para crear un solo envío usa POST /v1/orders.
Es multipart/form-data, no JSON. Envía dos campos: file (el .xlsx) y pickup_code (clave de retiro de 4 dígitos aplicada a todos los envíos). Mismo auth que POST /v1/orders: X-API-Key + sesión Shalom (header X-Shalom-Session o X-Shalom-Email/X-Shalom-Password).
Campos (form-data)
Campo Tipo Descripción file file (.xlsx) La plantilla Formato-Pro-Masivo con una fila por envío. Máximo 5 MB. (requerido) pickup_code string Clave de retiro de 4 dígitos que se asigna a todos los envíos del archivo (mismas reglas que en la orden única). (requerido)
Request curl -X POST https://api.shalom-api-peru.com/v1/orders/bulk \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
-F "file=@Formato-Pro-Masivo.xlsx" \
-F "pickup_code=2415"
200 OK {
"count": 12,
"message": "Envíos registrados",
"created": []
}
created siempre viene vacío: Shalom confirma la emisión pero no devuelve las guías. Para obtenerlas, consulta GET /v1/orders justo después — las del lote son las más recientes.
Validación todo-o-nada
Si cualquier fila tiene errores, no se crea ningún envío: la respuesta es 422 con el detalle por fila en rows para que corrijas el Excel y reintentes.
422 — filas con errores {
"error": {
"code": "upstream_rejected",
"message": "el archivo tiene filas con errores de validación",
"request_id": "01KQ..."
},
"rows": [
{
"row": 3,
"errors": ["El destinatario no tiene documento válido"]
},
{
"row": 7,
"errors": ["Terminal de destino no encontrado", "Peso requerido"]
}
]
}
Errores propios de bulk
HTTP code Cuándo se da 413 payload_too_large El archivo supera los 5 MB. 415 unsupported_media_type El body no es multipart/form-data. 422 upstream_rejected Hay filas con errores (detalle en rows). No se creó ningún envío.
El resto, en Errores.
GET/v1/orders
Lista las órdenes de la cuenta: preguías y envíos despachados. Sin query params devuelve todas en una sola respuesta, sin campo meta. Al mandar page o per_page se activa la paginación y se agrega meta.
Cuidado con cuentas grandes. Cada orden pesa ~3 KB: una cuenta con 5.000 envíos devuelve ~15 MB si no paginas. Usa per_page.
La paginación y los filtros se aplican del lado de la API, no de Shalom: recortan la respuesta, pero no reducen la carga contra el upstream.
Query params (opcionales)
Param Default Descripción page 1 Número de página. Mandar page o per_page activa la paginación y agrega meta. Una página fuera de rango devuelve "orders": [] con el meta correcto. per_page 20 Ítems por página. Tope máximo 200 (valores mayores se recortan a 200). guia — Filtra por match exacto del campo guia. status — Filtra por match exacto del código numérico de status (ej. 1). from — Fecha mínima (YYYY-MM-DD), inclusive. Filtra por la fecha de created_at. to — Fecha máxima (YYYY-MM-DD), inclusive. Filtra por la fecha de created_at.
Los filtros (guia, status, from, to) se combinan con AND y se aplican antes de paginar, así que meta.total refleja el conteo ya filtrado. Filtrar sin paginar devuelve el mismo shape de siempre (sin meta).
Request — sin params (lista completa) curl https://api.shalom-api-peru.com/v1/orders \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro"
200 OK {
"orders": [
{
"id": 87654321,
"internal_id": 4567890,
"guia": "12345678",
"serie": "s001",
"codigo": "ABCD",
"pickup_code": "2415",
"created_at": "2026-05-08 10:11:12",
"updated_at": "2026-05-08 10:11:13",
"shipping_date": "2026-05-08",
"status": 1,
"payer": "receiver",
"aereo": false,
"delivered": false,
"paid": false,
"origin": {
"ter_id": 404,
"name": "SALAS ICA",
"address": "SUB LOTE 01 ZONA PANAMERICANA SUR KM. 293.350...",
"abbreviation": "sls",
"phone": "(01) 500 7878",
"ubigeo": "ICA - ICA - SALAS"
},
"destination": {
"ter_id": 7,
"name": "AV PARRA 379 CO",
"address": "AV. PARRA 379",
"abbreviation": "AQP",
"phone": "0",
"ubigeo": "AREQUIPA - AREQUIPA - AREQUIPA"
},
"sender": {
"id": 1234567,
"document": "12345678",
"name": "JUAN",
"last_name": "PEREZ",
"sur_name": "GARCIA",
"full_name": "JUAN PEREZ GARCIA",
"phone": 999888777
},
"receiver": { "id": 7654321, "document": "87654321", "...": "..." },
"items": [
{
"id": 11223344,
"quantity": 1,
"weight": 0,
"width": 0,
"length": 0,
"height": 0,
"status": 1,
"product_name": "Sobre",
"product_detail": "Documentos simples en sobre manila / Tamaño A4",
"product_price": 20
}
],
"warranty": { "active": false, "amount": 0, "total_cost": 0, "percent": 0.01 }
}
]
}
Request — paginado + filtrado # Paginar (agrega "meta") + filtrar por estado y rango de fechas
curl "https://api.shalom-api-peru.com/v1/orders?page=1&per_page=20&status=1&from=2026-05-01&to=2026-05-31" \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro"
200 OK (con meta) {
"orders": [
{ "id": 87654321, "guia": "12345678", "status": 1, "created_at": "2026-05-08 10:11:12" }
],
"meta": {
"total": 142,
"page": 1,
"per_page": 20,
"last_page": 8
}
}
Campos de la orden
Campo Tipo Descripción id / internal_id / guia / serie / codigo / pickup_code — Identificadores del envío. Ver Identificadores. created_at / updated_at / shipping_date string Timestamps en formato Lima (YYYY-MM-DD HH:MM:SS y YYYY-MM-DD). status int Código numérico de estado de la orden (1 = creada, etc.). El significado lo define el flujo operativo de Shalom Pro. payer string "sender" o "receiver" (mapeado de REMITENTE/DESTINATARIO). aereo / delivered / paid bool Booleanos que indican si el envío es aéreo, ya fue entregado y/o ya fue pagado. origin / destination object Agencia con ter_id, name, address, abbreviation, phone, ubigeo. sender / receiver object Persona con id, document, name, last_name, sur_name, full_name, phone, email, address. items[] array Detalle por bulto: quantity, weight, width, length, height, product_name, product_detail, product_price. warranty object { active, amount, total_cost, percent }. Si la orden no tiene garantía, active es false.
DELETE/v1/orders/{id}
Borra una orden de la cuenta del cliente. Funciona tanto para borradores (preguías sin guía empresarial real) como para guías ya emitidas que aún no fueron recibidas en agencia.
{id} es el campo id de GET /v1/orders, no el ose_id ni la guia (ver Identificadores).
Operación destructiva. La orden no se puede recuperar una vez borrada.
Request curl -X DELETE https://api.shalom-api-peru.com/v1/orders/87654321 \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro"
200 OK {
"deleted": true,
"id": 87654321
}
El error propio de este endpoint es el 422: Shalom rechaza el borrado cuando la guía ya fue recibida en agencia o despachada. El resto, en Errores.
422 — Shalom rechaza el borrado {
"error": {
"code": "upstream_rejected",
"message": "Shalom Pro rechazó el borrado: shalompro: delete /delete-guia: La guia ya fue recibida en agencia",
"request_id": "01KQ..."
}
}
GET/v1/orders/{ose_id}/label
Descarga el rótulo (la etiqueta que se pega en el paquete) como PDF binario: Content-Type: application/pdf. El ose_id lo devuelve POST /v1/orders (ver Identificadores).
Request curl https://api.shalom-api-peru.com/v1/orders/1234567890/label \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
--output rotulo.pdf
Devuelve 404 si el ose_id no existe en la cuenta. Ver Errores.
GET/v1/orders/{ose_id}/voucher
Descarga el comprobante de la orden (resumen con datos de remitente, destinatario e items) como PDF. Mismo contrato que /label: Content-Type: application/pdf binario y mismo path param {ose_id}.
Request curl https://api.shalom-api-peru.com/v1/orders/1234567890/voucher \
-H "X-API-Key: tu-api-key" \
-H "X-Shalom-Email: cliente@empresa.com" \
-H "X-Shalom-Password: tu-password-de-shalom-pro" \
--output comprobante.pdf
Errores específicos
Mismos códigos que /label (400, 404, 502).
Campos del body
El remitente lo toma Shalom de la cuenta autenticada (X-Shalom-Email / la sesión que uses). El body solo lleva al destinatario en receiver, y un campo sender suelto se ignora. Única excepción: si mandas shipment_type: "empresarial", la guía se emite a nombre de una empresa remitente y ahí sí el sender es obligatorio (ver más abajo).
Requeridos
Campo Tipo Descripción origin_terminal_id int ID de la agencia de origen (campo id de GET /v1/agencies) destiny_terminal_id int ID de la agencia de destino (campo id de GET /v1/agencies) product_id int ID del producto (Sobre, Caja XXS/XS/S/M/L, Otra Medida). Listalo con GET /v1/products. receiver object Destinatario. Siempre debe incluir document_type + document (ver subcampos abajo). pickup_code string Clave de retiro de 4 dígitos. No puede ser repetido (1111..9999) ni consecutivo (1234..6789). declaracion_jurada string Tipo de contenido declarado — Shalom lo exige en toda orden. Acepta 4 alias cortos: "docs", "ropa", "art" (artículos de uso personal), "electro" (electrodomésticos); o los 4 textos literales que Shalom imprime en la guía ("Documentos", "Ropa", "Articulos de uso personal" sin tilde, "Electrodomésticos" con tilde). Si lo omites, la API responde 400 con los valores aceptados. (requerido)
Opcionales
Campo Tipo Descripción quantity int Default 1. shipment_type string Si lo omites, la guía se crea como siempre (remitente = la cuenta autenticada). Con "empresarial" se emite una guía empresarial a nombre de una empresa remitente, y pasa a ser obligatorio el campo sender. Ver Guía empresarial. sender object Solo se usa con shipment_type: "empresarial". Identifica a la empresa remitente: { "document_type": "RUC", "document": "20xxxxxxxxx" }. En el flujo normal se ignora. payer string "sender" (default, paga al despachar) o "receiver" (contra entrega). dimensions object Dimensiones custom { weight_kg, height_m, length_m, width_m } — valores numéricos (peso en kg, medidas en metros, ej. { "weight_kg": 2.5, "height_m": 0.3, "length_m": 0.4, "width_m": 0.2 }). Solo para producto "Otra Medida". aereo bool Servicio aéreo. Solo si origen y destino lo soportan. warranty object { "amount": "100.00" } activa garantía con monto declarado. collection_service object Cobro contra entrega. Objeto { cost, data } — ver subcampos abajo. Requiere cuenta bancaria registrada en Shalom Pro previamente. documentation array Guías adicionales: [{ "guide": "G123", "series": "S01" }]. contacto_doc string Documento de la persona que recoge.
Guía empresarial (remitente empresa)
Por defecto la guía se emite a nombre del titular de la cuenta (una persona), y eso no se puede cambiar: el flujo estándar de Shalom no acepta otro remitente. Si necesitas que salga a nombre de tu empresa, agrega estos dos campos al body — el resto queda igual:
"shipment_type": "empresarial",
"sender": { "document_type": "RUC", "document": "20xxxxxxxxx" }
El document es el RUC de la empresa que quieres que figure como remitente. Sin shipment_type, todo se comporta exactamente como antes.
Requisito previo: la empresa tiene que estar registrada y aprobada en tu cuenta de Shalom Pro (panel: Tu Negocio → Crear negocio — RUC, representante legal y documentos de respaldo; Shalom la aprueba manualmente). Si el RUC no está registrado, la API responde 404 con el mensaje "la empresa (RUC) no está registrada en la cuenta Shalom Pro".
Ten en cuenta que una guía empresarial es un producto distinto dentro de Shalom, no la misma guía con otro nombre impreso: tiene su propia tarifa y su propio flujo de emisión. El remitente empresa aparece en el comprobante (/voucher); el rótulo solo muestra destinatario y destino.
receiver (destinatario)
El destinatario (persona natural o empresa) siempre se identifica por documento: document_type + document son obligatorios, aunque pases también el id. Según lo que envíes:
- Solo
document_type + document: si el destinatario ya existe en la cuenta, se reusa. Si aún no existe, agrega también name y — solo para DNI/CE — last_name + sur_name para registrarlo. Opcionales: phone, email, address. - Con
id: si ya conoces su id (de GET /v1/persons/search o de un envío anterior), pásalo junto con document_type + document para evitar la búsqueda.
El remitente no va en el body: Shalom lo toma de la cuenta autenticada.
Empresas (RUC): la razón social va completa en name. last_name y sur_name no aplican.
Ejemplo: persona (DNI)
{
"document_type": "DNI",
"document": "12345678",
"name": "JUAN",
"last_name": "PEREZ",
"sur_name": "GARCIA",
"phone": 999888777
}
Ejemplo: empresa (RUC)
{
"document_type": "RUC",
"document": "20123456789",
"name": "MI EMPRESA S.A.C.",
"phone": 999888777
}
Campo Tipo Descripción id int person_id de Shalom Pro. Si lo pasas, los demás campos no son necesarios. document_type string "DNI" (8 dígitos), "RUC" (11 dígitos, empresas) o "CE" (carnet de extranjería). document string Solo dígitos para DNI/RUC; alfanumérico ≥4 chars para CE. name string Nombre (persona) o razón social completa (empresa). Obligatorio. last_name string Primer apellido. Obligatorio para DNI/CE, no aplica a RUC. sur_name string Segundo apellido. No aplica a RUC. phone int Teléfono numérico (sin código de país, ej. 999888777). email string Opcional. address string Opcional.
Servicio de cobranza (collection_service)
Cobro contra entrega: Shalom cobra al destinatario y deposita en la cuenta bancaria que indiques. Es un objeto con cost (el monto a cobrar) y data (los datos de la cuenta donde se deposita).
Requiere que la cuenta tenga el servicio de cobranza habilitado en pro.shalom.pe. Si no lo está, la orden falla con 422 upstream_rejected.
Campo Tipo Descripción cost number Monto a cobrar al destinatario (soles). Numérico, sin comillas. data.document string Documento del titular de la cuenta. data.name string Nombre del titular de la cuenta. data.bank string Banco: "BCP", "BBVA", "Interbank" o "Scotiabank". data.type_account string Tipo de cuenta: "Ahorro" o "Corriente". data.account_number string Número de cuenta. data.cci string Código de Cuenta Interbancario (CCI), 20 dígitos.
Ejemplo
{
"cost": 150.00,
"data": {
"document": "12345678",
"name": "JUAN PEREZ",
"bank": "BCP",
"type_account": "Ahorro",
"account_number": "1234567890",
"cci": "00212312345678901234"
}
}
Errores
Estructura consistente en todos los errores:
{
"error": {
"code": "not_found",
"message": "orden no existe",
"request_id": "01JXZ..."
}
}
HTTP code Descripción 400 bad_request Parámetros faltantes o inválidos 401 unauthorized API key inválida o ausente 401 shalom_auth_failed Credenciales de Shalom Pro ausentes o rechazadas (endpoints de tracking y /v1/orders) 403 forbidden Sin permisos 404 not_found Recurso no existe 409 conflict Conflicto de estado (ej. persona duplicada en /v1/orders) 413 payload_too_large Archivo demasiado grande (solo /v1/orders/bulk) 415 unsupported_media_type Content-Type no soportado (ej. /v1/orders/bulk espera multipart/form-data) 422 upstream_rejected Shalom Pro rechazó la solicitud por una regla de negocio 429 rate_limited Rate limit excedido 502 upstream_unavailable Shalom Pro no respondió o devolvió algo inesperado 502 shalom_unavailable Shalom Pro no disponible (solo /v1/orders) 504 upstream_timeout Shalom Pro tardó más de 30s en responder 500 internal Error interno
Rate Limits
Limite por defecto: 60 requests por minuto por API key.
Toda respuesta (no solo el 429) incluye los headers X-RateLimit-*, así sabes tu límite y cuánto te queda sin tener que chocar contra el error. Los exponemos vía Access-Control-Expose-Headers, así que también son legibles desde el browser.
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 55
X-RateLimit-Reset: 1713200060
Headers
Header Descripción X-RateLimit-Limit Requests por minuto de tu plan. X-RateLimit-Remaining Requests disponibles ahora mismo (capacidad de ráfaga restante). Llega a 0 cuando estás topeado. X-RateLimit-Reset Epoch en segundos (UTC) en que el cupo vuelve a estar lleno. Retry-After Solo en el 429: segundos a esperar antes de reintentar (mínimo 1).
Health Checks
Públicos, sin autenticación.
GET/healthz Liveness. 200 si el servidor está vivo.
GET/readyz Readiness. 200 cuando está listo para recibir tráfico.