← gocargo.com.ar

API de GoCargo

Versión 1 · https://www.gocargo.com.ar/api/v1

GoCargo conecta comercios de La Plata con cadetes que llevan sus envíos. Con esta API tu tienda online o tu sistema crea envíos, los sigue y cotiza sin pasar por la app, y recibe un aviso cada vez que un envío cambia de estado.

Todo va por HTTPS y en JSON. Las fechas son milisegundos desde 1970 (UTC) y los montos, pesos argentinos enteros.

Autenticación

Cada pedido lleva una API key de tu comercio. Se crea desde la app, en la sección API, y se muestra una sola vez: guardala en un lugar seguro, nunca en el código de una página web. Si la perdés, creá otra y revocá la vieja. Podés tener hasta 3 activas.

Authorization: Bearer gc_live_abc123_TU-SECRETO

Cada key tiene permisos: envios:crear (crear y cancelar), envios:leer y cotizar. Por defecto, los tres.

Cuotas. 120 pedidos por minuto y 5.000 por día por key, y 200 envíos creados por hora por comercio. Pasado un tope, 429 CUOTA_EXCEDIDA.

Errores

Siempre con la misma forma. El código no cambia; el mensaje, puede.

{
  "error": {
    "codigo": "DATOS_INVALIDOS",
    "mensaje": "Falta la dirección de entrega.",
    "detalle": { "campo": "entrega.direccion" }
  }
}
HTTPcodigocuándo
401KEY_INVALIDAFalta la key, está mal escrita, no existe o fue revocada. Todas contestan igual.
403SIN_PERMISOLa key existe pero no tiene el permiso que pide la ruta.
403COMERCIO_SUSPENDIDOLa cuenta del comercio no está activa.
403COMERCIO_SIN_VERIFICAREl comercio todavía no fue verificado por GoCargo.
403TERMINOS_PENDIENTESEl comercio tiene que aceptar los Términos vigentes, entrando a la app.
404NO_ENCONTRADONo existe un envío con ese código para tu comercio. El de otro comercio contesta igual.
409NO_CANCELABLEEl envío ya no se puede cancelar: lo tomó un cadete o ya terminó.
422DATOS_INVALIDOSAlgo del pedido está mal; detalle.campo dice qué.
422FUERA_DE_COBERTURANo pudimos cotizar ese recorrido: fuera de la zona de servicio o entre ciudades distintas.
422SIN_PRECIONo hay precio para ese recorrido con el tarifario de tu cadete.
422COMERCIO_SIN_CONFIGURARAl comercio le falta cargar su dirección de retiro en la app.
429CUOTA_EXCEDIDALlegaste a una cuota. Esperá y reintentá.
500ERROR_INTERNOUn problema nuestro. Reintentá en unos minutos.

Crear un envío

POST /api/v1/envios

El retiro es siempre la dirección de tu comercio: no se manda. El precio lo calcula GoCargo con la distancia real de la ruta; si tu cadete de cabecera tiene tarifario propio, rige el suyo.

curl -X POST https://www.gocargo.com.ar/api/v1/envios \
  -H "Authorization: Bearer gc_live_abc123_TU-SECRETO" \
  -H "Content-Type: application/json" \
  -d '{
    "entrega": {
      "direccion": "Calle 7 nro 1234, La Plata",
      "lat": -34.9214,
      "lng": -57.9545,
      "telefono": "2215550000"
    },
    "modalidad": "programado",
    "altoValor": false,
    "nota": "Timbre 2B",
    "referenciaExterna": "pedido-10482"
  }'

Respuesta 201:

{
  "codigo": "GC-7KQ2MX",
  "referenciaExterna": "pedido-10482",
  "prueba": false,
  "estado": "pendiente",
  "modalidad": "programado",
  "precio": 3500,
  "desglose": [ { "id": "base", "nombre": "Tarifa base", "monto": 3500 } ],
  "retiro": { "direccion": "Calle 50 nro 800, La Plata" },
  "entrega": { "direccion": "Calle 7 nro 1234, La Plata", "lat": -34.9214, "lng": -57.9545 },
  "km": 1.9,
  "altoValor": false,
  "valorDeclarado": null,
  "precinto": null,
  "conPin": false,
  "tracking": "https://www.gocargo.com.ar/t/GC-7KQ2MX#c=…",
  "creado": 1789590000000,
  "aceptado": null,
  "retirado": null,
  "entregado": null,
  "cancelado": null,
  "motivoCancelacion": null,
  "vencido": null
}

tracking es el link para mandarle a quien recibe: ve el estado del envío y, si lleva PIN, el PIN. Los envíos de prueba no tienen.

Listar envíos

GET /api/v1/envios

curl "https://www.gocargo.com.ar/api/v1/envios?limite=50&estado=entregado&desde=2026-10-01" \
  -H "Authorization: Bearer gc_live_abc123_TU-SECRETO"

Del más nuevo al más viejo. Filtros opcionales: desde y hasta (fecha ISO o milisegundos), estado y limite (de 1 a 100, por defecto 50).

{ "envios": [ … ], "siguiente": "eyJrIjoi…" }

Si siguiente no es null, pedí la página que sigue con cursor= y ese valor, y los mismos filtros. El cursor es opaco: no lo armes a mano. Con filtro de estado, una página puede traer menos envíos que el límite y aun así tener siguiente.

Consultar un envío

GET /api/v1/envios/{codigo}

curl https://www.gocargo.com.ar/api/v1/envios/GC-7KQ2MX \
  -H "Authorization: Bearer gc_live_abc123_TU-SECRETO"

Devuelve el envío con la misma forma que al crearlo.

Estados

pendienteCreado, esperando que lo tome un cadete.
aceptadoUn cadete lo tomó y va a buscarlo.
retiradoEl cadete lo retiró de tu comercio.
entregadoEntregado.
canceladoCancelado, con su motivo.
vencidoNadie lo tomó a tiempo. No se hizo: se vuelve a pedir.

Cancelar un envío

DELETE /api/v1/envios/{codigo}

curl -X DELETE https://www.gocargo.com.ar/api/v1/envios/GC-7KQ2MX \
  -H "Authorization: Bearer gc_live_abc123_TU-SECRETO" \
  -H "Content-Type: application/json" \
  -d '{ "motivo": "El cliente anuló la compra" }'

Solo mientras está pendiente. Una vez que un cadete lo tomó contesta 409 NO_CANCELABLE: para cancelarlo, escribinos. El motivo es opcional. Devuelve el envío cancelado.

Cotizar

POST /api/v1/cotizar

curl -X POST https://www.gocargo.com.ar/api/v1/cotizar \
  -H "Authorization: Bearer gc_live_abc123_TU-SECRETO" \
  -H "Content-Type: application/json" \
  -d '{
    "retiroLat": -34.9205, "retiroLng": -57.9536,
    "entregaLat": -34.9109, "entregaLng": -57.9543,
    "modalidad": "express"
  }'

Con key, cotiza con el tarifario de tu comercio si tiene uno. Sin key también funciona, con el precio de referencia y una cuota por IP. La cotización vale 10 minutos (expiraEn) y no reserva nada: el precio que rige es el que devuelve la creación del envío.

Ciudades

GET /api/v1/ciudades

curl https://www.gocargo.com.ar/api/v1/ciudades

Pública, sin key. Las ciudades donde funciona GoCargo, con sus zonas y sus precios de referencia vigentes.

Webhooks

Configurá una dirección https en la sección API de la app. Por cada envío creado después de configurarla, te mandamos un POST cuando cambia de estado. Tiene que ser una dirección pública: no se aceptan IPs privadas ni localhost.

envio.aceptadoUn cadete lo tomó y va a buscarlo.
envio.retiradoEl cadete lo retiró de tu comercio.
envio.entregadoLo entregó.
envio.canceladoSe canceló: desde la app, desde la API o desde GoCargo.
envio.incidenteHoy no se dispara nunca: está reservado. Preparate para recibirlo, pero no lo esperes.
POST /gocargo HTTP/1.1
Host: tu-tienda.com.ar
Content-Type: application/json
X-GoCargo-Evento: envio.entregado
X-GoCargo-Entrega: 9sKq2vXw…
X-GoCargo-Timestamp: 1789593616764
X-GoCargo-Firma: sha256=5d41402abc4b2a76b9719d911017c592…

{
  "evento": "envio.entregado",
  "envio": {
    "codigo": "GC-7KQ2MX",
    "referenciaExterna": "pedido-10482",
    "prueba": false,
    "estado": "entregado",
    "creado": 1789590000000,
    "aceptado": 1789590600000,
    "retirado": 1789591200000,
    "entregado": 1789593616000,
    "cancelado": null,
    "motivoCancelacion": null
  },
  "timestamp": 1789593616764
}

X-GoCargo-Entrega identifica el aviso y es el mismo en cada reintento.

Verificá siempre la firma. Es HMAC-SHA256, con el secreto del webhook (whsec_…, que también se muestra una sola vez), de <X-GoCargo-Timestamp>.<cuerpo tal cual llegó>. Calculala sobre el cuerpo crudo, antes de parsear el JSON, y rechazá los avisos con un timestamp de hace más de cinco minutos.

// Node.js
const crypto = require('crypto');

function esDeGoCargo(cuerpoCrudo, headers, secreto) {
  const ts = headers['x-gocargo-timestamp'];
  const esperada = 'sha256=' + crypto
    .createHmac('sha256', secreto)
    .update(`${ts}.${cuerpoCrudo}`)
    .digest('hex');
  const recibida = String(headers['x-gocargo-firma'] || '');
  return recibida.length === esperada.length
    && crypto.timingSafeEqual(Buffer.from(recibida), Buffer.from(esperada))
    && Math.abs(Date.now() - Number(ts)) < 5 * 60 * 1000;
}

Contestá un 2xx rápido. Esperamos hasta 5 s. Cualquier otra cosa —otro código, una redirección, un timeout— cuenta como fallo, y reintentamos a los 10 s, 60 s, 300 s. Si falla el último intento, lo vas a ver en la app como un aviso que no llegó. El envío sigue igual: lo que no llegó es el aviso.

Los avisos salen en segundos, no al instante, y el mismo aviso puede llegar más de una vez: usá X-GoCargo-Entrega para no procesarlo dos veces y, ante la duda, consultá el envío.

Verificación sin blockchain

GoCargo no usa blockchain para probar que algo no se tocó: usa HMAC-SHA256 con una clave propia. Es HONESTO sobre lo que eso prueba y lo que no: que un hash o un certificado salió de un servidor de GoCargo que tenía la clave, y que no cambió desde entonces. No prueba que una foto sea real ni que un cadete estuvo en un lugar — eso no tiene prueba criptográfica posible sin GPS en vivo, que GoCargo no usa.

Como es HMAC (una clave compartida, no un par de claves pública/privada), nadie fuera de GoCargo puede verificar una firma por su cuenta: hace falta preguntarle a un servidor de GoCargo, que es el único que tiene la clave. Las dos rutas de abajo son esa pregunta, hecha pública.

Prueba de entrega

Al entregar, GoCargo calcula SHA-256(código + hora + latitud + longitud + foto), en ese orden, y lo firma. Los dos quedan guardados en el envío y se muestran con la llave del seguimiento (/t/{codigo}#c={clave}): ahí hay un botón "Verificar autenticidad" que recalcula el hash en el navegador con lo que la pantalla tiene delante, y le pregunta al servidor si la firma es válida. No hay una ruta pública separada para esto: es parte del seguimiento.

Certificado de reputación

Desde su cuenta, un cadete puede descargar un JSON firmado con SUS números — nada de otro cadete, nada de un comercio en particular: cuántos viajes hizo, qué porcentaje con foto, su antigüedad, cuántos comercios captó y su escala de bonificación actual. Se lo lleva si se va: no tiene que pedirle a GoCargo una constancia, ni GoCargo tiene que dársela.

{
  "certificado": {
    "version": 1,
    "nombre": "Juan Pérez",
    "codigoAfiliacion": "JUAN-7K",
    "totalViajes": 842,
    "porcentajeConFoto": 97,
    "antiguedadDias": 214,
    "comerciosCaptados": 6,
    "escala": "experto",
    "escalaNombre": "Experto",
    "emitidoEn": 1789600000000
  },
  "firma": "5d41402abc4b2a76b9719d911017c592…"
}

Para confirmar que un certificado es genuino —que salió de GoCargo y no se editó después— mandá el mismo certificado y la misma firma, tal cual los recibiste, a esta ruta:

POST https://www.gocargo.com.ar/api/v1/certificados/verificar
Content-Type: application/json

{
  "certificado": { ... },
  "firma": "5d41402abc4b2a76b9719d911017c592…"
}

→ { "valido": true }

Pública, sin API key —quien pregunta no necesita cuenta en GoCargo—, acotada a 30 pedidos por minuto por IP. valido: false significa que el certificado no coincide con la firma: se editó un número, o la firma no es de GoCargo.

Lo que no sale por la API

Ningún teléfono —ni el de quien recibe ni el del cadete—, ni datos de cobro, ni documentos, ni quién es el cadete. Lo que necesitás del recorrido está en el estado y en el link de seguimiento.

¿Dudas o algo que no anda? Escribinos por WhatsApp. · Términos y Condiciones · Privacidad