GSG Corp · Integraciones

API de registro de pedidos

Versión 1.4 · Actualizado el 2026-09-29 · Endpoint: POST /api/v1/integration/orders (alias: POST /api/v1/orders/integration)

Documentación para el equipo técnico del integrador (plataforma de e-commerce, CRM, ERP o sistema propio del negocio) que enviará pedidos a GSG. No utiliza sesión web (JWT): la autenticación es API key y, para plataformas multi-tienda, token de tienda (store_token).

Compatibilidad: todos los cambios de esta versión son aditivos. Si ya estás integrado, tus peticiones actuales siguen funcionando sin cambios: mismas cabeceras, mismos campos, mismo envelope. Solo se agregan campos opcionales nuevos (apertura del paquete, cobro con POS, enlace de ubicación), valores nuevos (tamaños XL, identificación de agencia por código) y campos nuevos en la respuesta (en la 1.4: after_cutoff, que avisa si el pedido entró después de la hora límite del día). Ver Novedades.

1.Novedades de esta versión (1.4)

Novedades de la versión 1.3 (2026-09-25)

Novedades de la versión 1.2 (2026-09-15)

Novedades de la versión 1.1 (2026-09-03)

2.Flujo operativo (resumen)

Escenario A · Plataforma multi-tienda

  1. GSG da de alta un cliente de integración (la plataforma) y genera una API key (se muestra una sola vez). Esa clave identifica a la plataforma tecnológica (por ejemplo, su sistema de ventas).
  2. El negocio (tienda), en su panel GSG (Integraciones → Plataformas), se vincula a la plataforma y obtiene su store_token. Si la plataforma está configurada con aprobación manual, GSG aprueba el vínculo antes de habilitar el token.
  3. La plataforma obtiene el store_token de cada tienda: o el negocio lo pega en el panel de la plataforma, o la plataforma lo recupera automáticamente con POST /api/integration/bindings/lookup (ver Guía de inicio § 6).
  4. La plataforma configura en su sistema la API key (secreta, servidor a servidor) y el store_token de cada tienda conectada.
  5. Cada pedido se envía con POST /api/v1/orders/integration usando esas credenciales y el identificador del pedido en el e-commerce (order_external_id).
  6. Notificaciones de estado (webhook): GSG envía eventos a una URL única por plataforma (la configura un administrador GSG), firmados con HMAC. Deduplica por X-GSG-Event-Id: GSG puede reenviar eventos. Ver Manual de webhooks.

Escenario B · Integración directa

  1. El negocio solicita la integración desde su panel GSG (Integraciones → Integración directa).
  2. GSG aprueba la solicitud.
  3. El negocio genera su API key desde el panel (se muestra una vez). El store_token se muestra también pero es opcional: la API key ya identifica al negocio.
  4. Cada pedido se envía con POST /api/v1/orders/integration solo con la API key. El webhook lo configura el propio negocio en su panel.
Importante: la API key no debe exponerse en frontends públicos; idealmente solo en el backend del integrador o en un almacén seguro por tienda.

3.Endpoint

POST {BASE_URL}/api/v1/integration/orders API key + store_token (opcional en integración directa)

Sustituye {BASE_URL} por la URL base que te indique GSG (la de producción se muestra en el panel de negocios GSG). La ruta histórica POST {BASE_URL}/api/v1/orders/integration sigue vigente y es idéntica (mismo handler): los ejemplos de este documento valen para ambas.

Ruta retirada: la ruta anterior POST /api/integration/orders ya no existe. Apunta a /api/v1/orders/integration: el contrato (cabeceras, body, respuestas, idempotencia) es el mismo.

4.Cabeceras HTTP

CabeceraObligatoriaDescripción
Content-TypeSíapplication/json
AuthorizationSí*Bearer <API_KEY>
X-API-KeySí*Alternativa a Authorization: valor = API key completa. Si llegan ambas, prevalece X-API-Key.
X-Store-TokenPlataformas: sí**Token de tienda (st_…) generado desde el panel GSG al vincular la tienda. Opcional en integraciones directas (la API key ya identifica al negocio).
Idempotency-KeyNoRecomendada en producción: identificador único por intento de envío (máx. 100 caracteres; si excede, se trunca a 100). Alias: X-Idempotency-Key. Evita duplicar pedidos ante reintentos de red. Si no se envía, el sistema deriva una clave interna a partir del vínculo y de order_external_id. Una clave usada por un intento que falló (de otro pedido) queda liberada: no produce 409.

* Debe enviarse una de las dos formas de API key (no hace falta ambas).
** Si no usas X-Store-Token, puedes enviar el mismo valor en el cuerpo JSON como store_token.

Formato de la API key

La clave tiene el formato gsg_<prefijo_hexadecimal>_<secreto> y debe enviarse completa, tal como se generó.

5.Cuerpo JSON

5.1 Campos propios de la integración

CampoTipoObligatorioDescripción
order_external_idstringSíID del pedido en tu plataforma. Único por tienda vinculada. Máximo 120 caracteres. Es la llave de idempotencia y de consulta posterior. La comparación no distingue mayúsculas (ORD-1, ord-1 y ORD-1 con espacio final son el mismo pedido): envíalo siempre con la misma caja y sin espacios.
store_tokenstringNo*Mismo valor que X-Store-Token si prefieres mandarlo en el body en lugar de la cabecera.

* Plataformas: al menos uno entre X-Store-Token y store_token en body.

Todo lo demás es el mismo modelo que el registro de pedidos del panel GSG. El servidor valida campos extra según route_type.

Campos ignorados: id_client, products, business_id, headquarter_id, provider_user_id, id_package_size y flk_manage_products se descartan (tampoco participan en el hash de idempotencia). Un integrador no puede adjuntar el pedido a un cliente ya existente en GSG ni descontar stock: el destinatario se crea siempre con los datos del body.

5.2 Tipos de ruta (route_type) — cuándo usar cada uno

ValorCódigoNombrePrefijo trackingUso típico
1DELIVERYEntrega a domicilioGSG-E-Envío a domicilio del cliente final. Courier (moto) o GSG XL (van) según el tamaño.
2AGENCYEnvío por agenciaGSG-A-Envío a provincia vía empresa de transporte. Partner (Shalom, Olva, Marvisur): GSG lleva el paquete a la sucursal. Otra agencia: GSG lo lleva a la dirección de la agencia.
3EXCHANGECambioGSG-C-Entrega el paquete nuevo y recoge number_packages_in bultos del destinatario (cambio de talla, etc.).
4GSG_OFFICERecojo en sede GSGGSG-L-El destinatario retira en una sede GSG; no exige dirección ni distrito.
7FLEX_DELIVERYEntrega FlexGSG-F-Última milla estilo Mercado Libre Flex. Mismo cuerpo que el tipo 1; el servidor no añade validaciones extra.

Otros valores devuelven 400: route_type debe ser 1 (Entrega), 2 (Agencia), 3 (Cambio), 4 (Recojo en GSG) o 7 (Entrega Flex). Puede enviarse como número (1) o string ("1").

5.3 Modo de cobro recomendado: detallado (cost + advance)

CampoTipoDescripción
costnumber o string numéricoMonto total del pedido que el destinatario debe pagar (según tu regla de negocio). No negativo.
advancenumber o string numéricoAdelanto ya cobrado (si no hay adelanto, envía 0). No negativo.

El backend calcula el monto a cobrar en ruta como máximo(cost − advance, 0) (salvo PAGADO).

5.4 Catálogo de valores útiles

code_pay_method (obligatorio, texto): PAGADO, EFECTIVO, TARJETA, TRANSFERENCIA, YAPE, PLIN, OTRO. La lista vigente la devuelve GET /catalogs (payment_methods). El servidor normaliza a MAYÚSCULAS ("pagado" se procesa como PAGADO); aun así envía el código en mayúsculas.

size (o size_code): tamaño del bulto. Courier (moto): S, M (alias PEQUEÑO, MEDIANO; L/GRANDE solo compatibilidad). GSG XL (van): XL_GRANDE, XL_PLUS, XL_MAX, o XL + weight_kg, width_cm, height_cm, depth_cm por bulto para que GSG clasifique. Si lo omites se usa S. Detalle en § 6.

district (obligatorio en tipos 1, 3 y 7; en tipo 2 solo cuando la agencia se identifica por agency_name o no es partner): distrito de entrega, validado contra el catálogo de distritos GSG — el distrito determina la tarifa del servicio. Se normaliza a mayúsculas y la comparación no distingue tildes ("Miraflores", "MIRAFLORES" y "JESÚS MARÍA"/"JESUS MARIA" son equivalentes). Un distrito fuera de catálogo devuelve 400 con mensaje claro. En tipo 4 se ignora: el servidor lo fija según la sede. Lista vigente: GET /catalogs (districts).

client_pays_delivery: 0 = no paga delivery adicional; 1 = el cliente paga el delivery (informativo para el motorizado). Acepta número o string numérico (0, 1, "0", "1"); cualquier otro valor devuelve 400. En tipo 2 el servidor lo fuerza siempre a 0.

pay_at_destination (obligatorio en tipo 2): 0 o 1 — si el cobro del saldo es en destino (agencia). Acepta número o string numérico; cualquier otro valor devuelve 400.

package_registered, package_labeled (opcionales, tipo 2 partner): 0 o 1. Indican si el negocio ya registró el envío en la agencia y si ya rotuló el paquete. Si envías 0, GSG hace ese trabajo y lo cobra como recargo (registro S/ 2.00, rotulado S/ 0.50). Si los omites se asume trabajo hecho (no hay recargo). Solo tienen efecto con agencias partner. Se aceptan como número o string numérico; el valor entra al hash de idempotencia tal como lo envías (0 y "0" no son el mismo cuerpo), así que reintenta siempre con el mismo tipo JSON.

date_route (obligatorio): fecha y hora (con minutos) en que debe salir el pedido. Formatos aceptados (parsing estricto):

FormatoEjemplo
DD-MM-YYYY HH:mm (24 h, recomendado)16-01-2026 14:30
DD-MM-YYYY H:mm (24 h, hora sin cero inicial)16-01-2026 9:05
DD-MM-YYYY HH:mm:ss (24 h con segundos)16-01-2026 14:30:00
DD-MM-YYYY hh:mm:ss AM/PM16-01-2026 02:30:00 PM

Cualquier otro formato (p. ej. ISO 2026-01-16T14:30) u omitirlo devuelve 400 con mensaje descriptivo — el pedido no se registra con la fecha actual. La respuesta devuelve la fecha normalizada como YYYY-MM-DD HH:mm:ss.

5.4.1 Hora límite de registro del díav1.4

GSG recibe pedidos para despachar el mismo día hasta una hora límite (hora de Lima, America/Lima). La hora vigente está en GET /api/v1/integration/catalogs → order_cutoff ({"cutoff_time": "15:00", "timezone": "America/Lima"}; cutoff_time es null si no hay hora límite). GSG la puede cambiar: léela del catálogo, no la fijes en tu código.

order_number: opcional; máximo 120 caracteres. Si no lo envías, GSG copia order_external_id (truncado a 120). Se muestra en el panel y en el detalle del pedido.

sede (obligatorio en tipo 4): nombre de la sede GSG: ATE, LOS OLIVOS o LA VICTORIA (no distingue mayúsculas). Un valor fuera de esa lista devuelve 400. Direcciones en GET /catalogs (sedes).

Agencia (tipo 2): identifica la agencia con una de estas opciones:

CampoDescripción
agency_codeRecomendado. Código del catálogo (GET /catalogs → agencies[].code, p. ej. SHALOM, OLVA, MARVISUR, OTHER). La comparación con el catálogo no distingue mayúsculas, pero el valor entra al hash de idempotencia tal como lo envías: usa siempre la misma caja (recomendado: mayúsculas). Si envías OTHER debes enviar también agency_name con el nombre real de la agencia.
agency_idEntero ≥ 1 del catálogo (agencies[].id). Si envías agency_id y agency_code, deben corresponder a la misma agencia.
agency_nameNombre libre (máx. 100). Se compara sin tildes ni mayúsculas contra los aliases del catálogo: si coincide con un alias (p. ej. "Shalom", "Olva Courier") se resuelve esa agencia; si no coincide con ninguno se registra como "Otra agencia" con ese nombre. Un alias ambiguo devuelve 400. Con esta opción district es siempre obligatorio.
agency_branch_idOpcional. Sucursal del catálogo (agencies[].branches[].id) a la que GSG debe llevar el paquete.
destination_addressMáx. 250. Obligatorio solo si la agencia resuelta no es partner ("Otra agencia"): dirección de la agencia en Lima a la que GSG entrega. Para partners puede omitirse (GSG la lleva a la sucursal). Para provincia, útil como referencia de destino final (p. ej. Arequipa / Arequipa / Arequipa).
Partner vs otra agencia: una agencia es partner cuando agencies[].partner es true en el catálogo (Shalom, Olva, Marvisur). Con partner identificada por agency_code/agency_id, GSG no exige district, destination_address ni telephone (el contacto ocurre en la agencia destino); la dirección y el distrito se completan con la sede GSG que centraliza los envíos a agencias. Con "otra agencia", district y destination_address son obligatorios: definen a dónde va GSG.

5.5 Apertura del paquete, cobro con POS y enlace de ubicación

Tres campos opcionales. Si no los envías, el pedido se registra igual que en la versión 1.2.

CampoTipoObligatorioDescripción
open_policyv1.3stringNo ¿El destinatario puede abrir el paquete antes de recibirlo o pagarlo? SEALED = no se puede abrir (recibe el paquete cerrado). INSPECT = puede abrir y revisar el producto, sin usarlo ni probárselo (el motorizado espera hasta N minutos; hoy 3). TRY_ON = puede abrir y probarse el producto, pensado para ropa y calzado (hoy 5 minutos). La espera máxima la configura GSG y se publica en el catálogo (open_policy.options[].max_wait_minutes). Se acepta en minúsculas. Si lo omites, o envías null o "", se aplica el predeterminado que el negocio configuró en su perfil GSG (GET /catalogs → business.default_open_policy) y, si no configuró ninguno, SEALED. Aplica en los tipos 1, 3, 4 y 7; en tipo 2 (Agencia) GSG guarda null aunque lo envíes. Si el destinatario rechaza el producto después de abrirlo o probarlo, el motorizado lo registra como RECHAZADO con foto del producto.
pos_fee_includedv1.30/1 (número o string numérico)No Solo tiene efecto con code_pay_method = "TARJETA". 1 = el monto a cobrar ya incluye el 5% de comisión del POS (lo asume el destinatario); 0 = el negocio asume el 5%. Con cualquier otro método se guarda null. No cambia montos: GSG sigue descontando el 5% del cobro con tarjeta al entregar. Solo le indica al motorizado si el monto ya incluye la comisión.
url_mapsv1.3string (máx. 2000)No Enlace http(s) con la ubicación del destinatario (Google Maps, Apple Maps, ubicación de WhatsApp…). Se guarda y se muestra al motorizado; GSG puede convertirlo en un punto del mapa. Se ignora en tipo 4 (Recojo en sede GSG).

6.Tamaños: courier (S/M) y GSG XL

El campo size (alias size_code) define el vehículo y la tarifa: S y M viajan en moto y pagan la tarifa courier del distrito; las categorías XL viajan en van (GSG XL) y pagan la tarifa de la zona del distrito por categoría y por bulto. El tamaño no cambia el tipo de ruta: un XL puede ser entrega, agencia, cambio, recojo en sede o flex.

CódigoAlias aceptadosVehículoLímites por bultoPrecio
SPEQUEÑO, PEQUENO, PEQUENIO, CHICOMoto≤ 3 kg · hasta 30 × 20 × 12 cm (ver package_sizes)Tarifa courier del distrito (− descuento del negocio). Default si omites size.
MMEDIANOMoto≤ 3 kg · hasta 35 × 25 × 20 cmTarifa courier del distrito + recargo del tamaño (package_sizes[].extra_cost).
LGRANDEMotoSolo compatibilidad (legacy_only)Ídem M. No lo ofrezcas en tu UI.
XL_GRANDEXL GRANDEVan≤ 10 kg · lado mayor ≤ 60 cm · ≤ 0.216 m³districts[].xl.XL_GRANDE × bultos
XL_PLUSXL PLUSVan≤ 15 kg · lado mayor ≤ 80 cm · ≤ 0.512 m³districts[].xl.XL_PLUS × bultos
XL_MAXXL MAXVan≤ 25 kg · lado mayor ≤ 100 cm · ≤ 1.000 m³districts[].xl.XL_MAX × bultos
XLv1.2—VanExige weight_kg, width_cm, height_cm, depth_cm (> 0)GSG calcula la categoría y cobra como ella.

Los límites son los vigentes al publicar esta página; los actuales siempre están en package_sizes[] del catálogo (max_weight_kg, max_side_cm, max_volume_m3).

7.Matriz: qué es obligatorio según el validador

Si falta cualquiera de estos campos (cuando aplican), la API responde 400 con un mensaje que indica exactamente qué corregir (varios errores se concatenan con ". "). Toda la validación, incluida la que necesita base de datos (cobertura, agencia, tarifa XL), ocurre antes de reservar el order_external_id.

Obligatorios en todos los tipos de ruta

CampoNota
route_type1, 2, 3, 4 o 7
full_nameNombre completo del destinatario (máx. 150)
telephoneTeléfono del destinatario (máx. 15). No se exige en tipo 2 (el contacto ocurre en la agencia destino).
productDescripción del producto (máx. 500)
code_pay_methodMétodo de pago (§ 5.4)
date_routeFecha y hora, formato estricto (§ 5.4)

Obligatorios según el tipo de ruta

CampoTipo 1Tipo 2 partner
(por agency_code/agency_id)
Tipo 2 otra agencia
(por agency_name u OTHER)
Tipo 3Tipo 4Tipo 7
telephoneSí——SíSíSí
districtSí— (lo fija GSG)SíSí— (lo fija la sede)Sí
addressOperativo*—Operativo*Operativo*— (lo fija la sede)Operativo*
agency_code | agency_id | agency_name—Sí (código o id)Sí (agency_name)———
destination_address——Sí———
pay_at_destination—Sí (0/1)Sí (0/1)———
number_documentOpc.SíSíOpc.Opc.Opc.
package_registered, package_labeled—Opc. (0/1)————
agency_branch_id—Opc.————
number_packages_in———Sí (entero ≥ 1)——
sede————Sí (ATE | LOS OLIVOS | LA VICTORIA)—
sizeOpc. (S/M/L/XL_*)Opc.Opc.Opc.Opc.Opc.

* El validador no lo exige, pero sin address el motorizado no puede entregar: envíalo siempre en los tipos 1, 3 y 7 (y en "otra agencia" como dirección del destinatario final si aplica). Si envías latitude/longitude, address puede ir vacío (""); aun así ayuda al motorizado (número, Mz/Lt, dpto.).

8.Límites de longitud y formatos

Un valor más largo devuelve 400 <campo> supera el máximo de N caracteres (no se trunca). Estos límites también se publican en GET /catalogs → limits.

CampoMáx.CampoMáx.
order_external_id120product500
Idempotency-Key100 (se trunca)product_detail1000
full_name150observation250
telephone, other_telephone15pay_comments250
number_document30order_number120
address200destination_address250
address_reference350agency_name100
district50sede20
CampoFormato
number_packagesEntero ≥ 1 (default 1).
number_packages_inEntero ≥ 1 (tipo 3).
agency_id, agency_branch_idEntero ≥ 1.
cost, advance, pay_amount_simpleNúmero o string numérico ≥ 0.
pay_at_destination, client_pays_delivery, package_registered, package_labeled, pos_fee_included0/1 (número o string numérico).
latitude, longitudeOpcionales, numéricos. Coordenadas del destinatario; si están fuera de Perú se ignoran.
open_policyv1.3SEALED, INSPECT o TRY_ON (se aceptan minúsculas). Opcional.
url_mapsv1.3Enlace http:// o https:// sin espacios, máx. 2000 caracteres. Opcional.
other_telephone, address_reference, observation, product_detail, pay_commentsTexto opcional.

9.Ejemplos JSON por tipo

Cabeceras típicas en todos: X-API-Key (o Authorization), X-Store-Token (plataformas), Idempotency-Key. Si el token va en cabecera, omite store_token del body.

9.1 Tipo 1 — Entrega a domicilio (courier), modo detallado

Incluye los campos opcionales de la versión 1.3 (§ 5.5): el destinatario puede abrir y revisar el producto antes de pagar (open_policy: "INSPECT"), el saldo con tarjeta ya incluye el 5% del POS (pos_fee_included: 1) y la ubicación llega como enlace (url_maps). Si no los necesitas, omítelos.

{
  "order_external_id": "ORD-2026-778291",

  "route_type": 1,
  "full_name": "María López Sánchez",
  "telephone": "987654322",
  "other_telephone": "987654323",
  "address": "Jr. Los Olivos 456",
  "address_reference": "Cerca al parque central",
  "district": "MIRAFLORES",
  "number_document": "40123456",
  "observation": "Producto frágil, manejar con cuidado",

  "date_route": "16-01-2026 14:30",
  "code_pay_method": "TARJETA",
  "cost": "500.00",
  "advance": "200.00",

  "product": "Laptop HP",
  "product_detail": "Modelo HP Pavilion 15, color plateado",
  "number_packages": 1,
  "size": "M",
  "pay_comments": "Cliente pagó adelanto con tarjeta, saldo pendiente",
  "client_pays_delivery": 1,

  "open_policy": "INSPECT",
  "pos_fee_included": 1,
  "url_maps": "https://maps.app.goo.gl/Xk4bQ2mNcP8vRt7w9"
}

9.2 Tipo 1 — Entrega a domicilio con tamaño GSG XL

Solo cambia size. El precio sale de la zona del distrito (districts[].xl.XL_PLUS en el catálogo) × bultos. Si prefieres que GSG elija la categoría, reemplaza la última línea por "size": "XL", "weight_kg": 12, "width_cm": 58, "height_cm": 55, "depth_cm": 40 (medidas por bulto): la respuesta trae en size_code la categoría asignada.

{
  "order_external_id": "ORD-2026-778295",

  "route_type": 1,
  "full_name": "Carla Ruiz Paredes",
  "telephone": "987111222",
  "address": "Av. Benavides 1890, Dpto. 402",
  "address_reference": "Edificio con fachada blanca, frente a farmacia",
  "district": "MIRAFLORES",

  "date_route": "04-09-2026 10:30",
  "code_pay_method": "PAGADO",
  "cost": "0",
  "advance": "0",

  "product": "Silla de oficina ergonómica",
  "product_detail": "Caja 58 x 55 x 40 cm, 12 kg",
  "number_packages": 1,
  "size": "XL_PLUS"
}

9.3 Tipo 2 — Agencia partner por agency_code (recomendado)

Sin district, destination_address ni telephone: GSG traslada el paquete a la sucursal de Shalom. agency_branch_id es opcional (ver agencies[].branches en el catálogo). Con package_registered: 0 GSG registra el envío en la agencia y lo cobra como recargo.

{
  "order_external_id": "ORD-2026-778292",

  "route_type": 2,
  "agency_code": "SHALOM",
  "agency_branch_id": 3,
  "full_name": "Ana Martínez Quispe",
  "number_document": "87654321",
  "pay_at_destination": 1,
  "package_registered": 0,
  "package_labeled": 1,
  "destination_address": "Arequipa / Arequipa / Arequipa",

  "date_route": "18-01-2026 09:00",
  "code_pay_method": "TRANSFERENCIA",
  "cost": "300.00",
  "advance": "100.00",

  "product": "Ropa y accesorios",
  "product_detail": "3 polos, 2 pantalones, 1 par de zapatos",
  "number_packages": 2,
  "size": "L",
  "pay_comments": "Adelanto transferido, saldo se cobrará en destino",
  "observation": "Verificar estado de los productos antes de enviar"
}

9.4 Tipo 2 — Otra agencia por agency_name

El nombre no coincide con ningún alias del catálogo, así que se registra como "Otra agencia". GSG lleva el paquete a la dirección de la agencia en Lima (destination_address + district, ambos obligatorios). El mismo resultado se obtiene con "agency_code": "OTHER" más agency_name.

{
  "order_external_id": "ORD-2026-778296",

  "route_type": 2,
  "agency_name": "Transportes Cruz del Sur Cargo",
  "destination_address": "Av. Javier Prado Este 1155 (agencia Cruz del Sur Cargo)",
  "district": "LA VICTORIA",
  "full_name": "Luis Fernández Rojas",
  "number_document": "45678912",
  "pay_at_destination": 0,

  "date_route": "18-01-2026 09:00",
  "code_pay_method": "PAGADO",
  "cost": "0",
  "advance": "0",

  "product": "Repuestos automotrices",
  "number_packages": 1,
  "size": "M",
  "observation": "Entregar en ventanilla de encomiendas a nombre del destinatario"
}

9.5 Tipo 3 — Cambio

Debe incluir number_packages_in ≥ 1 (bultos que se recogen para el cambio).

{
  "order_external_id": "ORD-2026-778293",

  "route_type": 3,
  "full_name": "Pedro Gómez",
  "telephone": "987654328",
  "other_telephone": "987654329",
  "address": "Jr. Lima 147",
  "address_reference": "Segundo piso, departamento 201",
  "district": "BREÑA",

  "date_route": "20-01-2026 15:30",
  "code_pay_method": "YAPE",
  "cost": "180.00",
  "advance": "50.00",

  "product": "Camisa para cambio",
  "product_detail": "Camisa manga larga, color azul, talla M",
  "number_packages": 1,
  "number_packages_in": 2,
  "size": "S",
  "pay_comments": "Adelanto pagado por YAPE",
  "observation": "Recoger 2 camisas y entregar 1 camisa nueva"
}

9.6 Tipo 4 — Recojo en sede GSG

sede es el nombre de la sede: ATE, LOS OLIVOS o LA VICTORIA. Sin address/district: el servidor los completa con la dirección de la sede. Para PAGADO usa cost y advance en 0.

{
  "order_external_id": "ORD-2026-778294",

  "route_type": 4,
  "full_name": "Roberto Silva",
  "telephone": "987654331",
  "other_telephone": "987654332",
  "sede": "LOS OLIVOS",

  "date_route": "22-01-2026 14:00",
  "code_pay_method": "EFECTIVO",
  "cost": "450.00",
  "advance": "0.00",

  "product": "Paquete con productos electrónicos",
  "product_detail": "1 tablet, 2 auriculares, 1 cargador",
  "number_packages": 1,
  "size": "M",
  "pay_comments": "Cliente pagará al recoger",
  "observation": "Verificar identidad del cliente al recoger"
}

9.7 Tipo 7 — Entrega Flex

Mismo cuerpo que el tipo 1 (dirección, distrito, contacto, cost/advance). No hay campos extra por validador; mantén coherencia con tu operación de última milla.

{
  "order_external_id": "ML-2000012345678",

  "route_type": 7,
  "full_name": "Diana Torres Vega",
  "telephone": "987222333",
  "address": "Calle Los Cedros 250",
  "address_reference": "Casa de dos pisos, portón negro",
  "district": "SAN BORJA",
  "latitude": -12.0985,
  "longitude": -77.0012,

  "date_route": "05-09-2026 08:00",
  "code_pay_method": "PAGADO",
  "cost": "0",
  "advance": "0",

  "product": "Zapatillas running talla 40",
  "number_packages": 1,
  "size": "S",
  "order_number": "2000012345678"
}

9.8 Modo simple (opcional, no prioritario)

Alternativa al detallado: un solo campo pay_amount_simple (string o número) con el monto a cobrar, cuando code_pay_method no es PAGADO. No mezcles con cost/advance si quieres que prevalezca el detallado: vacía pay_amount_simple o no lo envíes.

9.9 Referencia rápida de campos comunes

CampoNotas
order_external_id, store_tokenIntegración (§ 5.1).
route_type1, 2, 3, 4, 7 (§ 5.2). Obligatorio.
cost, advanceModo detallado (§ 5.3).
full_name, product, code_pay_method, date_routeObligatorios en todos los tipos (§ 7).
telephoneObligatorio salvo en tipo 2.
districtObligatorio en 1, 3, 7 y en agencia no partner / por nombre; validado contra catálogo y define la tarifa (§ 5.4).
addressRecomendado en tipos con dirección; en tipo 4 y partner lo fija GSG.
size / size_codeS, M (L compat), XL_GRANDE, XL_PLUS, XL_MAX o XL + peso/medidas (§ 6). Default S.
weight_kg, width_cm, height_cm, depth_cmv1.2Peso y medidas por bulto (números ≥ 0). Obligatorios con size: "XL"; opcionales en el resto.
number_documentObligatorio tipo 2; opcional en otros.
agency_code / agency_id / agency_name, agency_branch_id, destination_address, pay_at_destination, package_registered, package_labeledSolo tipo 2 (§ 5.4).
number_packages_inSolo tipo 3 (obligatorio).
sedeSolo tipo 4 (obligatorio).
latitude, longitudeOpcionales (§ 8).
open_policyv1.3Opcional: SEALED, INSPECT, TRY_ON. Tipos 1, 3, 4 y 7; en tipo 2 se guarda null. Sin enviar: predeterminado del negocio (§ 5.5).
pos_fee_includedv1.3Opcional, 0/1. Solo con TARJETA; informativo (§ 5.5).
url_mapsv1.3Opcional, enlace http(s) ≤ 2000. Se ignora en tipo 4 (§ 5.5).

10.Idempotencia y order_external_id

Estado del intento previoMismo cuerpoCuerpo distinto
Procesado (200)200 replay de la respuesta guardada409 "usado con otro contenido"
En proceso (< 5 min)409 "se está procesando"409 "se está procesando"
En proceso huérfano (> 5 min)Se retoma y reejecutaSe retoma y reejecuta
Fallido (400 tardío o 5xx)Se reejecutaSe reejecuta con el nuevo contenido

Recomendación: usa siempre la cabecera Idempotency-Key única por intento lógico (p. ej. UUID) y reintenta con la misma clave si hay timeout de red.

11.Respuestas exitosas

11.1 HTTP 200 — Pedido registrado

{
  "message": { "description": "Ok", "title": "OK OK", "code": "90200" },
  "data": {
    "order_external_id": "ORD-2026-778295",
    "message": "Pedido guardado exitosamente",
    "id_route": 231472,
    "id_route_type": 1,
    "code_tracking": "GSG-E-231472",
    "route_type_code": "DELIVERY",
    "size_code": "XL_PLUS",
    "service": "XL",
    "date_route": "2026-09-04 10:30:00",
    "after_cutoff": false,
    "status": { "id": 3, "code": "REGISTRADO", "name": "REGISTRADO", "final": false },
    "service_cost": {
      "currency": "PEN",
      "total": 28,
      "base_cost": 28,
      "package_extra_cost": 0,
      "agency_handling_cost": 0,
      "agency_registration_cost": 0,
      "agency_labeling_cost": 0,
      "pricing_rule": "XL_ZONE_TARIFF_V1"
    },
    "tracking_url": null,
    "open_policy": "SEALED"
  }
}
CampoDescripción
order_external_idEl id que enviaste.
id_routeIdentificador interno del envío en GSG.
id_route_typeTipo de ruta numérico (1, 2, 3, 4, 7).
code_trackingCódigo de seguimiento GSG (GSG-E-231472). Muéstralo al comprador y úsalo en soporte.
route_type_codev1.1DELIVERY, AGENCY, EXCHANGE, GSG_OFFICE, FLEX_DELIVERY.
size_codev1.1Tamaño canónico registrado (S, M, L, XL_GRANDE, XL_PLUS, XL_MAX). Con size: "XL" es la categoría que GSG asignó.
servicev1.1COURIER o XL.
date_routev1.1Fecha programada normalizada, YYYY-MM-DD HH:mm:ss.
after_cutoffv1.4true si el pedido es para hoy y se registró después de la hora límite (§ 5.4.1): quedó fuera de hora y GSG puede despacharlo el siguiente día hábil. false en el resto.
statusv1.1Estado inicial: siempre REGISTRADO (id 3). Ver catálogo de estados.
service_costv1.1Tarifa del servicio GSG para este envío (lo que GSG cobra al negocio), IGV incluido. total = suma de los componentes. pricing_rule: regla aplicada (DISTRICT_BASE_V1, XL_ZONE_TARIFF_V1, AGENCY_FIXED_V1, AGENCY_FIXED_XL_V1, AGENCY_MINIMUM_V1, AGENCY_DISTRICT_SURCHARGE_V1, AGENCY_LEGACY_DISTRICT_V1, GSG_OFFICE_V1, GSG_OFFICE_XL_V1, BUSINESS_AGREEMENT_V1). No incluye lo que el destinatario paga por el producto.
tracking_urlv1.1URL pública de rastreo si GSG tiene habilitada la página de rastreo; null en caso contrario. No construyas la URL por tu cuenta: usa este campo.
open_policyv1.3Apertura del paquete guardada: la que enviaste o, si no la enviaste, el predeterminado del negocio (SEALED si no configuró ninguno). null en tipo 2 (Agencia). En el ejemplo el pedido no envió open_policy.

11.2 HTTP 200 — Replay idempotente

Si el pedido ya fue procesado correctamente con el mismo order_external_id y el mismo cuerpo, la respuesta es igual a la almacenada la primera vez (misma estructura que arriba, incluidos los campos nuevos si el pedido se registró con esta versión).

11.3 HTTP 200 — Caso marginal sin cuerpo guardado

En situaciones excepcionales podría devolverse un objeto mínimo { "replay": true, "route_id": 231472 }; no es el flujo normal tras un registro completo.

12.Errores (referencia)

Todas las respuestas de error siguen el patrón (sin data):

{
  "message": {
    "description": "Texto explicativo",
    "title": "Error | Unauthorized Error | Too Many Requests | Error Server",
    "code": "90400 | 90401 | 90409 | 90429 | 90500"
  }
}

La tabla consolidada de todos los endpoints está en Referencia de errores. Resumen para el registro:

12.1 HTTP 401 — Autenticación / credenciales

Situaciónmessage.description
Falta API keyAPI key requerida (Authorization Bearer o X-API-Key)
Formato de clave incorrectoFormato de API key inválido
Clave incorrectaAPI key no válida
Secreto revocado (rotación)API key revocada o inactiva
Integración directa aún no aprobadaIntegración pendiente de aprobación por GSG
Integración directa rechazadaIntegración rechazada por GSG
Cliente de integración desactivadoCliente de integración inactivo
Plataforma sin token de tiendastore_token requerido (X-Store-Token o body.store_token)
Token no pertenece a esa API keystore_token no vinculado a esta API key
API key con fecha de expiración vencidaAPI key expirada; genere una nueva
Vínculo pendiente / rechazado / bloqueado / desactivadoVínculo de tienda inactivo o bloqueado (pendiente de aprobación por GSG) · Vínculo de tienda inactivo o bloqueado (rechazado por GSG) · Vínculo de tienda inactivo o bloqueado (bloqueado por GSG) · Vínculo de tienda inactivo o bloqueado (desactivado por el negocio) (prefijo histórico común; el paréntesis indica el estado)
Integración directa sin negocio activoLa integración directa no tiene un negocio activo; contacte a GSG

Un fallo interno al validar credenciales (p. ej. base de datos caída) responde 500 Error validando credenciales de integración, no 401. Un 401 siempre significa que las credenciales enviadas son inválidas.

12.2 HTTP 400 — Validación de negocio / payload

SituaciónDescripción típica
JSON malformado o cuerpo demasiado grandeEl cuerpo JSON no es válido
order_external_id ausente o > 120order_external_id es obligatorio (máximo 120 caracteres)
Falta un campo obligatorio comúnfull_name es obligatorio (nombre completo del destinatario), product es obligatorio (descripción del producto a enviar), code_pay_method es obligatorio (método de pago, ej. EFECTIVO, PAGADO, YAPE)… concatenados con .
date_route ausente o inválidodate_route "..." no tiene un formato válido; use DD-MM-YYYY HH:mm en 24 horas (ej. 16-01-2026 14:30) o DD-MM-YYYY hh:mm:ss AM/PM (ej. 16-01-2026 02:30:00 PM)
size fuera de catálogosize "XXL" no es válido; valores permitidos: S (PEQUEÑO), M (MEDIANO), L (GRANDE), XL (con weight_kg, width_cm, height_cm y depth_cm por bulto: GSG clasifica), XL_GRANDE, XL_PLUS, XL_MAX (si lo omite se usa S/PEQUEÑO)
"XL" sin peso o medidassize XL requiere weight_kg, width_cm, height_cm y depth_cm por bulto (mayores a 0) para calcular la categoría; o envíe directamente XL_GRANDE, XL_PLUS o XL_MAX
Bulto mayor que XL MaxEl bulto (58×55×40 cm, 30 kg) supera XL Max: es Especial / Cargo y se cotiza con operaciones.
XL deshabilitadosize: el servicio GSG XL no está disponible por integración en este momento; use S, M o L
district ausentedistrict es obligatorio (distrito de entrega; define la tarifa del servicio)
district fuera de catálogodistrict "..." no existe en el catálogo de distritos GSG; verifique el nombre (ej. MIRAFLORES) o consulte GET /api/v1/integration/catalogs
Distrito sin cobertura XLEl distrito "..." no tiene cobertura GSG XL; requiere cotización manual.
Flags con valor no 0/1pay_at_destination debe ser 0 o 1 (se acepta número o string numérico); se recibió "..."
Campos del tipo de rutaagency_id, agency_code o agency_name es requerido para ruta tipo Agencia · pay_at_destination es requerido para ruta tipo Agencia · number_document es requerido para ruta tipo Agencia · destination_address es requerido para ruta tipo Agencia · number_packages_in es requerido y debe ser mayor a 0 para ruta tipo Cambio · sede es requerido para ruta tipo Recojo en GSG
Agencia inexistente / no disponibleLa agencia indicada por agency_id o agency_code no existe o está inactiva · La agencia indicada no está disponible para nuevos envíos · El alias de agencia "..." es ambiguo · agency_name es requerido cuando se selecciona Otra agencia · agency_id y agency_code no corresponden a la misma agencia
Partner sin tarifa XL para la categoríaLa agencia ... no tiene tarifa XL configurada para ... (coordina con GSG)
Sede GSG inválida (tipo 4)La sede GSG "..." no es válida. Sedes permitidas: ATE, LOS OLIVOS, LA VICTORIA.
Largo excedido<campo> supera el máximo de N caracteres
Enteros / montos / coordenadas inválidosnumber_packages debe ser un entero mayor o igual a 1; se recibió "..." · cost debe ser un monto numérico no negativo; se recibió "..." · latitude debe ser numérico; se recibió "..."
open_policy fuera de catálogov1.3open_policy "ABIERTO" no es válido; valores permitidos: SEALED, INSPECT, TRY_ON
pos_fee_included distinto de 0/1v1.3pos_fee_included debe ser 0 o 1 (se acepta número o string numérico); se recibió "..."
url_maps inválidov1.3url_maps debe ser un enlace http(s) de hasta 2000 caracteres (ej. https://maps.app.goo.gl/...)

12.3 HTTP 409 — Conflictos / idempotencia

SituaciónDescripción típica
Mismo order_external_id, pedido ya procesado, distinto cuerpoorder_external_id ya fue usado con otro contenido; use otro id o reenvíe el mismo cuerpo
Petición en cursoEste pedido se está procesando; espere y reintente con el mismo payload
Idempotency-Key reutilizada en otro pedido (procesado o en proceso)Idempotency-Key ya usada para otro order_external_id; use una clave nueva por pedido (si el intento anterior falló, la clave se libera y no hay 409)
Duplicado genéricoPetición duplicada (idempotencia); consulte el resultado previo o Conflicto de registro duplicado

12.4 HTTP 429 — Rate limit

Dos límites: por cliente de integración (Demasiadas peticiones: máximo 300 por minuto por cliente de integración. Espere y reintente con backoff., evaluado tras autenticar con tu API key) y por IP (Demasiadas peticiones desde esta IP; espere y reintente con backoff, 900/min, evaluado antes de autenticar). Revisa las cabeceras RateLimit / RateLimit-Policy. Detalle en Guía de inicio § 7.

12.5 HTTP 500 — Error de servidor

Los 500 llevan siempre un texto fijo; el detalle interno del servidor nunca se expone al integrador.

SituaciónDescripción típica
Fallo al registrar (BD, etc.)Error al registrar el pedido; reintente en unos segundos
Error validando el distrito o pre-cotizandoError validando el distrito del pedido · Error validando el pedido; reintente en unos segundos
Error interno validando credencialesError validando credenciales de integración
Error en capa de idempotenciaError de idempotencia

Ante un 500 puedes reintentar con el mismo order_external_id y el mismo cuerpo: nada quedó registrado a medias.

12.6 Reintento tras un fallo previo

13.Ejemplo curl (tipo 1, modo detallado)

curl -X POST "https://{BASE_URL}/api/v1/orders/integration" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: gsg_PREFIJO_SECRETO_COMPLETO" \
  -H "X-Store-Token: st_TOKEN_DE_TIENDA" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "order_external_id": "PED-2026-0001",
    "route_type": 1,
    "full_name": "María Pérez",
    "telephone": "987654321",
    "address": "Av. Ejemplo 123",
    "address_reference": "Frente al parque",
    "district": "MIRAFLORES",
    "date_route": "04-09-2026 10:30",
    "code_pay_method": "EFECTIVO",
    "cost": "150.00",
    "advance": "0.00",
    "product": "Pedido ecommerce",
    "number_packages": 1,
    "size": "S"
  }'

Integración directa: omite -H "X-Store-Token: …".

14.Buenas prácticas para el integrador

  1. Guarda la API key en un vault o variables de entorno; nunca en repositorios ni frontends.
  2. Por tienda, guarda el store_token de forma segura (o que el negocio lo pegue en su panel privado).
  3. Cotiza antes de registrar con POST /quote si tu flujo muestra el costo de envío al negocio, y valida distritos y agencias contra GET /catalogs (cacheado 5 min).
  4. Reintentos con backoff ante 409 "en proceso", 429 o errores de red, siempre con la misma Idempotency-Key.
  5. Registra order_external_id, id_route, code_tracking y service_cost.total devueltos para trazabilidad, conciliación y soporte.
  6. Usa siempre HTTPS y valida certificados en producción.
  7. Para el estado del pedido, webhooks primero y consulta por API como respaldo.
  8. Tolera campos nuevos en las respuestas: el contrato crece de forma aditiva.
  9. Respeta la hora límite del día (GET /catalogs → order_cutoff): después de esa hora propone al negocio la fecha del día siguiente y avísale si un pedido volvió con after_cutoff: true.

15.Contacto

Para URL base de producción, ambiente de pruebas, ampliación de tipos de ruta o dudas de negocio, coordina con GSG (integraciones directas: desde el panel; plataformas: con el administrador de integraciones que entregó la API key). Esta documentación describe el comportamiento técnico del endpoint implementado.

16.Historial de cambios

VersiónFechaCambios
1.42026-09-29 Hora límite de registro del día (§ 5.4.1): un pedido para hoy registrado después de la hora límite de GSG (GET /catalogs → order_cutoff) se acepta igual pero queda fuera de hora. Respuesta 200 con el campo nuevo after_cutoff (booleano). Sin cambios en el cuerpo, las cabeceras ni los errores.
1.32026-09-25 Campos opcionales nuevos (antes se descartaban sin error): open_policy (apertura del paquete: SEALED/INSPECT/TRY_ON; sin enviar se aplica el predeterminado del negocio y, si no hay, SEALED; null en Agencia), pos_fee_included (0/1, solo con TARJETA; informativo, no cambia montos) y url_maps (enlace http(s) ≤ 2000; se ignora en tipo 4). Con latitude/longitude, address puede ir vacío. Respuesta 200 con open_policy efectivo. 400 nuevos para valores inválidos de los tres campos.
1.22026-09-15 Alias POST /api/v1/integration/orders (la ruta histórica se mantiene). GSG XL sobre el modelo de zonas: categorías XL_GRANDE/XL_PLUS/XL_MAX con tarifa por zona del distrito y por bulto (XL_ZONE_TARIFF_V1; XL_STD deja de ofrecerse); size: "XL" + weight_kg/width_cm/height_cm/depth_cm con clasificación automática; weight_kg opcional en S/M con 400 si supera el máximo de moto; L marcado legacy_only; reglas nuevas en pricing_rule (GSG_OFFICE_XL_V1, BUSINESS_AGREEMENT_V1).
1.12026-09-03 Revisión del mismo día: alias PEQUENIO para S; agency_code/agency_name/package_registered/package_labeled ya no se normalizan antes del hash (entran tal como llegan); regla "misma caja" para order_external_id (comparación sin distinguir mayúsculas); una Idempotency-Key de un intento fallido se libera; 401 de vínculo con prefijo Vínculo de tienda inactivo o bloqueado (…) y 401 API key expirada; genere una nueva; 400 El cuerpo JSON no es válido; 429 en dos niveles (300/min por cliente + 900/min por IP); 500 con texto fijo Error al registrar el pedido; reintente en unos segundos.
1.12026-09-03 Cambios aditivos: tamaños GSG XL (XL_STD, XL_PLUS, XL_GRANDE, XL_MAX); agencia por agency_code/agency_id, sucursal agency_branch_id, flags package_registered/package_labeled; en agencia partner ya no se exigen district, destination_address ni telephone; validación completa (incluida pre-cotización) antes de reservar el order_external_id y regla "un intento fallido nunca bloquea"; límites de longitud con 400 claro; validación de enteros, montos y coordenadas; campos nuevos en la respuesta (route_type_code, size_code, service, date_route, status, service_cost, tracking_url); rate limit 300/min (429); mensajes 401 para integraciones directas y estados de vínculo; escenario de integración directa (store_token opcional). Ruta POST /api/integration/orders retirada (ya anunciado).
1.02026-07-14 Versión inicial publicada como documento interno API de registro de pedidos — Integración GSG (B2B): autenticación API key + store_token, tipos 1/2/3/4/7, modo de cobro detallado, matriz de obligatorios, idempotencia, respuestas y errores, lookup de tiendas.