Cotizar
POST/api/v1/cotizar
Calcula el costo de envío a un municipio específico antes de crear la guía. Útil para mostrar el precio al usuario final o validar que el municipio tiene cobertura.
Body
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
ciudadDestino | string (2–100 chars) | Requerido | Nombre del municipio de destino |
La búsqueda es case-insensitive y acepta coincidencias parciales: "mix" encuentra "Mixco".
Ejemplo
curl
curl -X POST https://api.tpcxpress.com/api/v1/cotizar \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{ "ciudadDestino": "Villa Nueva" }'Respuesta 200 Municipio con tarifa personalizada
{
"success": true,
"data": {
"municipio": "Villa Nueva",
"municipioEncontrado": true,
"costoBase": 30.00,
"costoFinal": 25.00,
"esPersonalizado": true,
"diferencia": -5.00
}
}Respuesta 200 Municipio con tarifa base
{
"success": true,
"data": {
"municipio": "Mixco",
"municipioEncontrado": true,
"costoBase": 30.00,
"costoFinal": 30.00,
"esPersonalizado": false,
"diferencia": 0.00
}
}Error 400 Municipio sin cobertura
Si ciudadDestino no tiene cobertura activa, la API retorna:
{
"success": false,
"error": {
"message": "No tenemos cobertura activa en \"Chiquimula\". Consulta GET /municipios para ver las ciudades disponibles.",
"code": "MUNICIPIO_NO_CUBIERTO"
}
}Usa GET /municipios para obtener la lista de destinos con cobertura activa antes de cotizar.
Campos de respuesta
| Campo | Tipo | Descripción |
|---|---|---|
municipio | string | Nombre normalizado del municipio encontrado |
municipioEncontrado | boolean | Siempre true — si no hay cobertura, la API retorna 400 |
costoBase | number | Tarifa base de envío de tu empresa (en Quetzales) |
costoFinal | number | Costo real a aplicar para este envío |
esPersonalizado | boolean | true si se aplica una tarifa negociada específica para este municipio |
diferencia | number | costoFinal - costoBase. Negativo = descuento, positivo = recargo |
Lógica de cálculo
- Busca el municipio en el catálogo activo por nombre (insensible a mayúsculas, match parcial)
- Si no se encuentra o está inactivo →
400 MUNICIPIO_NO_CUBIERTO - Si la empresa tiene una tarifa personalizada activa para ese municipio → usa esa tarifa
- Si no hay tarifa personalizada → usa el
costoEntregabase configurado para la empresa
Las tarifas personalizadas por municipio se configuran en el panel de administración y se negocian con el equipo TPC. Consulta tus tarifas en GET /api/v1/empresa.
Integración en tu UI (selector de destino)
// Mostrar costo al usuario mientras escribe el municipio
async function calcularCosto(ciudadDestino) {
if (ciudadDestino.length < 3) return null
const res = await fetch('https://api.tpcxpress.com/api/v1/cotizar', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.TPC_API_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ ciudadDestino }),
})
if (!res.ok) {
const { error } = await res.json()
if (error?.code === 'MUNICIPIO_NO_CUBIERTO') return null // sin cobertura
throw new Error(error?.message ?? `HTTP ${res.status}`)
}
const { data } = await res.json()
return data
}
// Uso
const costo = await calcularCosto('Mixco')
if (!costo) console.log('Sin cobertura en ese municipio')
else console.log(`Envío a ${costo.municipio}: Q ${costo.costoFinal.toFixed(2)}`)
// "Envío a Mixco: Q 25.00"Relación con creación de guías
El endpoint POST /api/v1/cotizar y POST /api/v1/guias usan la misma lógica de cálculo de costos. Si cotizas "Mixco" y obtienes Q 25.00, la guía que crees para Mixco tendrá ese mismo costoServicio.
La cotización no reserva nada — es solo una consulta. Puedes cotizar sin límite.