GSG Corp · Integraciones

Seguimiento y cancelación de pedidos

Versión 1.2 · Actualizado el 2026-09-29 · Prefijo: /api/v1/integration/orders

Estos endpoints te permiten consultar el estado y la historia de cada pedido que registraste por API, listar pedidos por rango de fechas y cancelar un pedido mientras GSG aún no lo haya recibido. Solo ves los pedidos creados por API con la misma tienda (o el mismo negocio, en integración directa).

1.Detalle por order_external_id

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

Devuelve el pedido completo: cabecera, destinatario, agencia, cobro, estado actual, estado logístico, línea de tiempo con fotos, pagos registrados, incidencias y costo del servicio. Si el order_external_id contiene caracteres especiales, codifícalo en la URL (encodeURIComponent).

curl
curl "https://{BASE_URL}/api/v1/integration/orders/ORD-2026-778291" \
  -H "X-API-Key: gsg_PREFIJO_SECRETO" \
  -H "X-Store-Token: st_TOKEN_DE_TIENDA"
Respuesta 200
{
  "message": { "description": "Ok", "title": "OK OK", "code": "90200" },
  "data": {
    "order_external_id": "ORD-2026-778291",
    "id_route": 231472,
    "code_tracking": "GSG-E-231472",
    "order_number": "ORD-2026-778291",
    "route_type": { "id": 1, "code": "DELIVERY", "name": "ENTREGA" },
    "service": "COURIER",
    "size_code": "M",
    "size_name": "Mediano",
    "date_register": "2026-09-03 15:00",
    "date_route": "2026-09-04 10:30",
    "after_cutoff": false,
    "product": "Laptop HP",
    "product_detail": "Modelo HP Pavilion 15, color plateado",
    "number_packages": 1,
    "number_packages_in": null,
    "recipient": {
      "full_name": "María López Sánchez",
      "telephone": "987654322",
      "other_telephone": "987654323",
      "number_document": "40123456",
      "district": "MIRAFLORES",
      "address": "Jr. Los Olivos 456",
      "address_reference": "Cerca al parque central",
      "url_maps": "https://maps.app.goo.gl/Xk4bQ2mNcP8vRt7w9",
      "location": { "lat": -12.1211, "lng": -77.0301 }
    },
    "open_policy": "INSPECT",
    "agency": null,
    "payment": {
      "code_pay_method": "TARJETA",
      "cost": 500,
      "advance": 200,
      "pay_amount": 300,
      "client_pays_delivery": true,
      "pos_fee_included": 1
    },
    "current_state": {
      "id": 9, "code": "EN_RUTA", "name": "EN RUTA",
      "date": "2026-09-04 09:12", "route_state_id": 888994, "final": false
    },
    "logistic_state": { "code": "READY_DISPATCH", "label": "Listo para despacho" },
    "timeline": [
      { "route_state_id": 888100, "id": 3, "code": "REGISTRADO", "name": "REGISTRADO",
        "date": "2026-09-03 15:00", "date_rescheduled": null, "comment": "", "photos": [] },
      { "route_state_id": 888700, "id": 6, "code": "DRIVER_ASIGNADO", "name": "DRIVER ASIGNADO",
        "date": "2026-09-04 08:30", "date_rescheduled": null, "comment": "", "photos": [] },
      { "route_state_id": 888994, "id": 9, "code": "EN_RUTA", "name": "EN RUTA",
        "date": "2026-09-04 09:12", "date_rescheduled": null, "comment": "",
        "photos": ["https://storage.googleapis.com/…?X-Goog-Signature=…"] }
    ],
    "payments": [
      { "code_pay_method": "TARJETA", "pay_amount": 200, "detail": "Adelanto",
        "collected_by": "PROVIDER", "label": "Tarjeta directo al negocio", "date": "2026-09-03 15:00" }
    ],
    "incidents": [],
    "service_cost": { "currency": "PEN", "total": 12 },
    "cancellable": false,
    "tracking_url": null
  }
}
CampoDescripción
route_typeid numérico, code (DELIVERY, AGENCY, EXCHANGE, GSG_OFFICE, FLEX_DELIVERY) y nombre interno. El tipo puede cambiar si soporte GSG lo modifica; el id_route no.
service, size_code, size_nameCOURIER/XL y tamaño canónico con su nombre.
date_register, date_routeYYYY-MM-DD HH:mm, hora de Lima.
after_cutoffv1.2true si el pedido es para el día en que se registró y entró después de la hora límite (API de pedidos § 5.4.1): quedó fuera de hora. Si GSG cambia la fecha del pedido, se recalcula.
number_packages_inBultos a recoger (tipo 3); null en el resto.
recipientDatos del destinatario tal como los enviaste; los teléfonos se guardan normalizados (solo dígitos y +, sin espacios/guiones; a un número local de 11 dígitos que empieza en 51 se le quita el prefijo). Cadenas vacías cuando no aplica.
recipient.url_mapsv1.1Enlace de ubicación que enviaste en url_maps; null si no lo enviaste (o en tipo 4).
recipient.locationv1.1Punto vigente del destinatario { lat, lng }: el que enviaste al registrar (latitude/longitude) o el que fijó después el motorizado. null si no hay punto.
open_policyv1.1Apertura del paquete guardada: SEALED, INSPECT, TRY_ON o null (Agencia o pedidos anteriores al cambio). Ver API de pedidos § 5.5.
agencySolo tipo 2: { name, destination_address, pay_at_destination }; null en otros tipos.
paymentModalidad de cobro registrada: método, cost, advance, pay_amount (a cobrar en ruta) y client_pays_delivery.
payment.pos_fee_includedv1.1Solo con TARJETA: 1 = el monto a cobrar ya incluye el 5% del POS; 0 = el negocio asume el 5%; null con otro método o si no se indicó.
current_stateÚltimo estado: id, code, name, date, route_state_id (mismo id que llega en el webhook; estrictamente creciente por pedido) y final.
logistic_stateEstado logístico interno (dónde está físicamente el paquete). Ver § 6.
timelineTodos los estados en orden ascendente por route_state_id. comment trae el motivo de reprogramación/incidencia que el motorizado o soporte registró; date_rescheduled la nueva fecha (YYYY-MM-DD) cuando el estado es REPROGRAMADO; photos son URLs firmadas y temporales (caducan a los ~20 minutos): descárgalas o vuelve a consultar, no las guardes como enlace permanente.
paymentsCobros registrados: collected_by = GSG (lo cobró el motorizado; se liquida al negocio) o PROVIDER (lo cobró el negocio directamente). label es un texto listo para mostrar.
incidentsIncidencias abiertas o cerradas: status, resolution, subcategory_code, text, date, date_closed. Las notas internas de soporte no se exponen.
service_cost.totalTarifa del servicio GSG efectivamente cargada al negocio (puede incluir ajustes posteriores de soporte).
cancellabletrue si el pedido todavía puede cancelarse por API (ver § 4).
tracking_urlURL pública de rastreo o null.

Errores: 404 Error: No existe un pedido con ese identificador para esta tienda si el pedido no fue creado por API con esta tienda (o fue eliminado). Respuesta con Cache-Control: no-store.

2.Detalle por código de tracking

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

Misma respuesta que el detalle anterior, buscando por code_tracking (p. ej. GSG-E-231472; no distingue mayúsculas). También acepta el id_route numérico (231472): útil si soporte cambió el tipo de ruta y con él el prefijo del código. El alcance es el mismo: solo pedidos de tu tienda creados por API.

curl "https://{BASE_URL}/api/v1/integration/orders/tracking/GSG-E-231472" \
  -H "X-API-Key: gsg_PREFIJO_SECRETO" \
  -H "X-Store-Token: st_TOKEN_DE_TIENDA"

3.Listado paginado

GET {BASE_URL}/api/v1/integration/orders?from=&to=&state=&page=&limit= API key + store_token (opcional en integración directa)
QueryObligatorioDescripción
fromNoYYYY-MM-DD. Filtra por fecha de registro del pedido. Default: to − 6 días.
toNoYYYY-MM-DD, inclusive. Default: hoy. Rango máximo 92 días.
stateNoFiltra por el último estado del pedido. Acepta el code (EN_RUTA), el nombre con espacios (EN RUTA) o el id (9).
pageNo≥ 1. Default 1.
limitNo1–100. Default 50.
curl
curl "https://{BASE_URL}/api/v1/integration/orders?from=2026-09-01&to=2026-09-03&state=EN_RUTA&page=1&limit=50" \
  -H "X-API-Key: gsg_PREFIJO_SECRETO" \
  -H "X-Store-Token: st_TOKEN_DE_TIENDA"
Respuesta 200
{
  "message": { "description": "Ok", "title": "OK OK", "code": "90200" },
  "data": {
    "from": "2026-09-01",
    "to": "2026-09-03",
    "state": "EN_RUTA",
    "page": 1,
    "limit": 50,
    "total": 123,
    "orders": [
      {
        "order_external_id": "ORD-2026-778291",
        "id_route": 231472,
        "code_tracking": "GSG-E-231472",
        "order_number": "ORD-2026-778291",
        "route_type_code": "DELIVERY",
        "service": "COURIER",
        "size_code": "M",
        "date_register": "2026-09-03 15:00",
        "date_route": "2026-09-04 10:30",
        "after_cutoff": false,
        "recipient_name": "María López Sánchez",
        "district": "MIRAFLORES",
        "current_state": { "id": 9, "code": "EN_RUTA", "name": "EN RUTA", "final": false,
                           "date": "2026-09-04 09:12", "route_state_id": 888994 },
        "logistic_state": { "code": "READY_DISPATCH", "label": "Listo para despacho" },
        "tracking_url": null
      }
    ]
  }
}

Orden: del pedido más reciente al más antiguo. total es el número de pedidos que cumplen el filtro; recorre las páginas hasta page × limit ≥ total. Errores 400: from debe tener formato YYYY-MM-DD, to debe tener formato YYYY-MM-DD, from debe ser anterior o igual a to, El rango máximo es de 92 días, state no existe en el catálogo; consulte GET /api/v1/integration/catalogs (states).

4.Cancelar un pedido

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

Body opcional: { "reason": "texto ≤ 250" }. El motivo queda en la historia del pedido como "Cancelado por el integrador: …".

Regla: un pedido solo puede cancelarse por API mientras GSG no tenga el paquete: su último estado debe ser REGISTRADO (3) o RECOJO_PENDIENTE (4), el ingreso a almacén aún no debe haberse producido y el día del pedido no debe estar calculado/liquidado por GSG. En ese caso pasa al estado INACTIVO (id 2), se emite el webhook route.status_changed (después de confirmarse la cancelación) y no se cobra el servicio. Dos cancelaciones simultáneas del mismo pedido no duplican el estado: la segunda responde already_cancelled: true. Si el paquete ya fue recolectado, ya ingresó a GSG o ya tiene motorizado asignado, la API responde 409: coordina la cancelación con soporte GSG (retorno del paquete, cobro de tarifa según el caso).
curl
curl -X POST "https://{BASE_URL}/api/v1/integration/orders/ORD-2026-778291/cancel" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: gsg_PREFIJO_SECRETO" \
  -H "X-Store-Token: st_TOKEN_DE_TIENDA" \
  -d '{ "reason": "El comprador anuló la compra" }'
Respuesta 200 · cancelado
{
  "message": { "description": "Ok", "title": "OK OK", "code": "90200" },
  "data": {
    "order_external_id": "ORD-2026-778291",
    "id_route": 231472,
    "code_tracking": "GSG-E-231472",
    "cancelled": true,
    "already_cancelled": false,
    "status": { "id": 2, "code": "INACTIVO", "name": "INACTIVO", "final": true },
    "note": "El pedido quedó INACTIVO (cancelado antes de ingresar a GSG). Recibirá el webhook route.status_changed correspondiente."
  }
}
Respuesta 200 · ya estaba cancelado (idempotente)
{
  "message": { "description": "Ok", "title": "OK OK", "code": "90200" },
  "data": {
    "order_external_id": "ORD-2026-778291",
    "id_route": 231472,
    "cancelled": true,
    "already_cancelled": true,
    "status": { "id": 2, "code": "INACTIVO", "name": "INACTIVO", "final": true }
  }
}
HTTPmessage.descriptionSituación
200—Cancelado (already_cancelled: false) o ya estaba INACTIVO/CANCELADO (already_cancelled: true).
400reason supera el máximo de 250 caracteresMotivo demasiado largo.
404Error: No existe un pedido con ese identificador para esta tiendaEl pedido no es de tu tienda o no fue creado por API.
409El pedido ya está en estado final (ENTREGADO) y no puede cancelarse por APIÚltimo estado RECHAZADO o ENTREGADO.
409El pedido ya está en proceso (RECOLECTADO) y no puede cancelarse por API; coordine con soporte GSGEl último estado ya no es REGISTRADO ni RECOJO_PENDIENTE (recolectado, motorizado asignado, en ruta…).
409El pedido ya fue recibido por GSG (o está en un estado que no admite cancelación automática); coordine la cancelación con soporte GSGEl paquete ya ingresó a GSG. Contacta a soporte.
409El pedido pertenece a un día ya liquidado por GSG y no admite cancelación automática; coordine con soporteEl pedido está en un día ya calculado/liquidado; solo soporte GSG puede modificarlo.
409El pedido ya está en un estado final y no puede cancelarse por APIEl estado final se detectó al ejecutar la cancelación (carrera con un cambio de estado).
409El pedido no admite cancelación automática; coordine con soporte GSGOtra regla de negocio impidió la cancelación.
500Error al cancelar el pedidoFallo interno (texto fijo). Reintenta: la cancelación es idempotente.

Los 409 nunca incluyen datos internos de GSG (motorizados, instrucciones del panel): decide por el código HTTP y muestra el texto tal cual si te sirve.

Consulta cancellable en el detalle del pedido para saber de antemano si la cancelación por API es posible.

5.Catálogo de estados (state_tracking)

Son los estados que aparecen en current_state, timeline, en el filtro state del listado y en new_status/state_id de los webhooks. Los estados finales no admiten un estado posterior.

idcodeNombreQué significa para el vendedorFinal
3REGISTRADOREGISTRADOEl pedido fue creado en GSG y está pendiente de ingresar al almacén (por recojo en tu local o porque lo lleves a una sede). Estado inicial de todo pedido.No
4RECOJO_PENDIENTERECOJO PENDIENTEGSG programó el recojo del paquete en tu local; aún no lo tiene.No
5RECOLECTADORECOLECTADOGSG ya tiene el paquete (lo recogió o lo recibió en sede). A partir de aquí no se puede cancelar por API.No
17ALISTADOALISTADOPaquete preparado en almacén para salir a reparto.No
6DRIVER_ASIGNADODRIVER ASIGNADOUn motorizado/conductor tiene asignada la entrega. Se notifica por webhook.No
18DRIVER_DESASIGNADODRIVER DESASIGNADOSe retiró la asignación; el pedido volverá a asignarse. No requiere acción. Se notifica por webhook.No
9EN_RUTAEN RUTAEl motorizado salió a entregar el pedido.No
10EN_EL_PUNTOEN EL PUNTOEl motorizado llegó a la dirección del destinatario.No
7PENDIENTEPENDIENTENo se pudo concretar la entrega en este intento (no contesta, ausente, etc.); queda pendiente de un nuevo intento. Revisa comment.No
11REPROGRAMADOREPROGRAMADOLa entrega se reprogramó para otra fecha (date_rescheduled, motivo en comment). Avisa al comprador.No
15INCIDENCIASINCIDENCIASHay una incidencia que impide continuar (dirección incorrecta, datos incompletos, paquete no coincide…). Revisa incidents y contacta a soporte si te lo piden.No
16CORREGIDOCORREGIDOLa incidencia fue resuelta; el pedido continúa su flujo.No
14ENTREGADOENTREGADOEntregado al destinatario (puede haber foto en timeline[].photos). Cobro registrado en payments.Sí
13RECHAZADORECHAZADOEl destinatario rechazó el paquete. GSG lo devolverá al negocio.Sí
1DEVOLUCIONDEVOLUCIONEl paquete está en proceso de devolución al negocio (tras rechazo, intentos fallidos o cancelación posterior al ingreso).No
12PERDIDOPERDIDOEl paquete se extravió; GSG gestiona el reclamo contigo.No
8CANCELADOCANCELADOPedido cancelado después de que GSG lo recibió (por GSG o a pedido del negocio vía soporte). Puede seguir un flujo de devolución.Sí
2INACTIVOINACTIVOPedido anulado antes de ingresar a GSG (cancelación por API o desde el panel). No se cobra el servicio.Sí

Estados finales: INACTIVO (2), CANCELADO (8), RECHAZADO (13), ENTREGADO (14). El campo detail del catálogo (GET /catalogs → states) trae un texto listo para mostrar al comprador.

6.Estados logísticos

Complementan al estado de seguimiento indicando dónde está físicamente el paquete dentro de la operación de GSG. Los devuelven logistic_state en el detalle y el listado. Son informativos: para decidir en tu sistema usa el estado de seguimiento; el logístico ayuda a explicar (por ejemplo, un CANCELADO con CANCELED_RETURN_PENDING significa que el paquete aún no volvió a tu local).

codelabelSignificado
AT_PROVIDERPendiente de ingreso a almacén GSGEl paquete sigue en poder del negocio.
ENTRY_CANCELEDIngreso canceladoEl ingreso se anuló (p. ej. cancelación por API antes del recojo).
IN_WAREHOUSEEn almacén GSGRecibido en una sede GSG.
READY_DISPATCHListo para despachoAsignado/alistado para salir a reparto o en reparto.
IN_TRANSITEn tránsito entre sedesMovimiento interno entre sedes GSG.
DELIVEREDEntregadoEntregado al destinatario.
CANCELED_RETURN_PENDINGCancelado, pendiente de devolución al almacénSe canceló estando fuera; el paquete debe volver a almacén.
CANCELED_RETURNEDCancelado, devuelto al almacénEl paquete cancelado ya está en almacén GSG.
CHANGE_PENDINGCambio pendiente de ingresoTipo 3: se entregó y falta que ingresen los bultos recogidos.
CHANGE_COMPLETEDCambio completado, en almacénTipo 3: los bultos recogidos ya están en almacén.
RETURN_IN_TRANSITEn ruta de devolución al proveedorGSG está devolviendo el paquete al negocio.
RETURNED_PROVIDERDevuelto al proveedorEl negocio ya recibió el paquete de vuelta.
DUPLICATEDRuta duplicadaSoporte marcó el pedido como duplicado de otro.
REUSEDRuta reutilizadaEl paquete se reutilizó en otra ruta (contenedores).
TRANSFERREDTransferido a otra rutaEl paquete continúa bajo otro id_route; consulta a soporte.
DAMAGEDPaquete dañadoSe reportó daño; soporte gestiona contigo.
LOSTPaquete perdidoSe reportó pérdida; soporte gestiona contigo.
UNKNOWNSin informaciónSin estado logístico calculado (pedidos antiguos).

7.Recomendaciones: webhook primero, polling de respaldo

  1. Webhook como fuente principal. Configura el evento route.status_changed (manual): recibes cada cambio en segundos, con route_state_id para ordenar y state_id/new_status para actualizar tu pedido sin llamar a la API.
  2. Polling solo como respaldo. Cada 15 minutos (o menos frecuente), llama a GET /orders?from=&to= para los pedidos no finales de los últimos días y concilia current_state.route_state_id con lo que tienes guardado. Esto cubre webhooks que no pudiste recibir (tu servidor caído, firma mal verificada) hasta que GSG los reenvíe.
  3. Usa el detalle (GET /orders/:id) cuando necesites fotos, cobros o incidencias: por ejemplo al recibir el webhook de ENTREGADO, para obtener la foto de entrega, o al recibir INCIDENCIAS/REPROGRAMADO, para leer el motivo.
  4. Ordena siempre por route_state_id, nunca por hora: los reportes offline del motorizado pueden llegar tarde.
  5. Deja de consultar los pedidos con current_state.final = true.
  6. Respeta el rate limit (300/min por cliente de integración, 900/min por IP): un listado de 100 pedidos cada 15 min es una llamada; consultar el detalle de cada pedido en bucle no lo es.

8.Historial de cambios

VersiónFechaCambios
1.22026-09-29 API 1.4: el detalle (por order_external_id y por código de tracking) y cada pedido del listado agregan after_cutoff (booleano: registrado para hoy después de la hora límite). El webhook no cambia.
1.12026-09-25 API 1.3: el detalle (por order_external_id y por código de tracking) agrega open_policy, recipient.url_maps, recipient.location ({ lat, lng } o null) y payment.pos_fee_included (0/1/null). El listado y el webhook no cambian.
1.02026-09-03 Revisión del mismo día: tabla completa de 409 de cancelación con los textos vigentes (día liquidado, estado final, no admite cancelación automática) sin datos internos; regla de cancelación incluye el día no calculado/liquidado y el webhook se emite tras confirmar; cancelaciones simultáneas no duplican estado; los teléfonos del destinatario se guardan normalizados; DRIVER_ASIGNADO y DRIVER_DESASIGNADO ahora se notifican por webhook; rate limit por cliente de integración.
1.02026-09-03 Versión inicial: GET /orders/:orderExternalId, GET /orders/tracking/:codeTracking, GET /orders (paginado), POST /orders/:orderExternalId/cancel, catálogo de los 18 estados y de los estados logísticos, recomendaciones de seguimiento.