Tu primera guía
Crea un envío, compara cotizaciones y compra tu primera guía en modo de prueba — de cero a PDF en minutos.
Aquí creas tu primera guía de envío en modo de prueba. El modo de prueba usa paqueterías simuladas y saldo virtual. No se mueve dinero real. Los pasos en producción son los mismos. Para pasar a producción, cambia la llave.
Necesitas una cuenta de SendIt y tu llave de prueba (sk_test_...). La encuentras en el dashboard, en Configuración → Llaves de API, o vía GET /v1/api-keys.
Crea un envío
Un envío describe origen, destino y paquete. La respuesta trae el envío recién creado y rates[]. En rates[] vienen las cotizaciones de todas las paqueterías disponibles para esa ruta.
curl -X POST https://api.sendit.mx/v1/shipments \
-H "X-API-Key: sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"from": {
"contactName": "Almacén CDMX",
"contactPhone": "+5215512345678",
"street": "Av. Insurgentes Sur",
"exteriorNumber": "1602",
"neighborhood": "Crédito Constructor",
"city": "Ciudad de México",
"state": "CDMX",
"postalCode": "03940",
"country": "MX"
},
"to": {
"contactName": "María López",
"contactPhone": "+5213312345678",
"street": "Av. López Mateos",
"exteriorNumber": "45",
"neighborhood": "Jardines del Sol",
"city": "Zapopan",
"state": "JAL",
"postalCode": "45050",
"country": "MX"
},
"parcel": { "length": 30, "width": 20, "height": 15, "weight": 2.5 }
}'const response = await fetch("https://api.sendit.mx/v1/shipments", {
method: "POST",
headers: {
"X-API-Key": process.env.SENDIT_API_KEY, // sk_test_...
"Content-Type": "application/json",
},
body: JSON.stringify({
from: {
contactName: "Almacén CDMX",
contactPhone: "+5215512345678",
street: "Av. Insurgentes Sur",
exteriorNumber: "1602",
neighborhood: "Crédito Constructor",
city: "Ciudad de México",
state: "CDMX",
postalCode: "03940",
country: "MX",
},
to: {
contactName: "María López",
contactPhone: "+5213312345678",
street: "Av. López Mateos",
exteriorNumber: "45",
neighborhood: "Jardines del Sol",
city: "Zapopan",
state: "JAL",
postalCode: "45050",
country: "MX",
},
parcel: { length: 30, width: 20, height: 15, weight: 2.5 },
}),
});
const { data: shipment } = await response.json();
console.log(shipment.id, shipment.rates.length);La respuesta (recortada) trae el envío en estado DRAFT y sus cotizaciones:
{
"success": true,
"data": {
"id": "clxq1w2e3r4t5y6u7i8o9p0a",
"status": "DRAFT",
"rates": [
{
"id": "DHL_standard_a1b2c3",
"carrierCode": "DHL",
"serviceCode": "EXPRESS_WORLDWIDE",
"serviceName": "DHL Express Nacional",
"serviceLevel": "standard",
"totalPrice": 326.82,
"currency": "MXN",
"estimatedDays": { "min": 1, "max": 2 },
"expiresAt": "2026-07-18T14:30:00.000Z"
},
{
"id": "ESTAFETA_economy_x9y8z7",
"carrierCode": "ESTAFETA",
"serviceCode": "TERRESTRE",
"serviceName": "Estafeta Terrestre",
"serviceLevel": "economy",
"totalPrice": 289.50,
"currency": "MXN",
"estimatedDays": { "min": 3, "max": 5 },
"expiresAt": "2026-07-18T14:30:00.000Z"
}
],
"ratesStatus": "ready",
"ratesExpiresAt": "2026-07-18T14:30:00.000Z"
}
}Elige una cotización
Cada elemento de rates[] es una oferta en firme. Su totalPrice incluye IVA y es exactamente lo que se debitará de tu monedero. Elige por precio, por velocidad o por paquetería. Para el siguiente paso solo necesitas el id de la tarifa.
const cheapest = shipment.rates
.slice()
.sort((a, b) => a.totalPrice - b.totalPrice)[0];
console.log(cheapest.id); // "ESTAFETA_economy_x9y8z7"Las cotizaciones son válidas 24 horas. Si expiran, pide unas frescas con GET /v1/shipments/:id/rates?refresh=true.
Compra la guía
Envía el rateId elegido. El encabezado Idempotency-Key es opcional, pero mándalo en esta llamada. Si tu petición se interrumpe y la reintentas con la misma llave, no habrá doble cargo.
curl -X POST https://api.sendit.mx/v1/shipments/clxq1w2e3r4t5y6u7i8o9p0a/label \
-H "X-API-Key: sk_test_..." \
-H "Idempotency-Key: 1f0e6f0e-59a4-4a6f-9d2e-9b1a7b2c3d4e" \
-H "Content-Type: application/json" \
-d '{ "rateId": "ESTAFETA_economy_x9y8z7" }'const purchase = await fetch(
`https://api.sendit.mx/v1/shipments/${shipment.id}/label`,
{
method: "POST",
headers: {
"X-API-Key": process.env.SENDIT_API_KEY,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({ rateId: cheapest.id }),
}
);
const { data: label } = await purchase.json();
console.log(label.trackingNumber, label.labelUrl);{
"success": true,
"data": {
"shipmentId": "clxq1w2e3r4t5y6u7i8o9p0a",
"labelId": "clxlbl456abc789def012ghi",
"trackingNumber": "TEST-ESTAFETA-A1B2C3D4",
"labelUrl": "https://labels.sendit.mx/test/clxq1w2e3r4t5y6u7i8o9p0a/TEST-ESTAFETA-A1B2C3D4.pdf",
"carrierCode": "ESTAFETA",
"serviceName": "Estafeta Terrestre",
"charged": "289.50",
"currency": "MXN",
"walletBalanceAfter": "9710.50",
"breakdown": {
"ivaAmount": "39.93",
"overageCharge": "0.00",
"total": "289.50"
}
}
}Descarga el PDF de labelUrl. Esa es tu guía. El cargo salió del saldo virtual de prueba, no de dinero real.
Ve tu envío avanzar
En modo de prueba el paquete simula su viaje solo. Va de PICKED_UP a DELIVERED en menos de media hora. Para no esperar, avanza el estado a mano:
curl -X POST https://api.sendit.mx/v1/shipments/clxq1w2e3r4t5y6u7i8o9p0a/test/advance-status \
-H "X-API-Key: sk_test_..."Cada llamada avanza un paso:
LABEL_PURCHASED → READY_FOR_PICKUP → PICKED_UP → IN_TRANSIT → OUT_FOR_DELIVERY → DELIVEREDConsulta el estado y el historial de eventos en cualquier momento con GET /v1/shipments/:id.