Guías de la Tolls API
Todo lo necesario para integrar el cálculo de peajes por API o MCP: autenticación, cobro por créditos, errores y límites.
Actualizado
⚡ Quickstart
- Crea una cuenta en el dashboard (dash.tolls.cargoffer.com).
- Recarga créditos (o canjea un cupón) desde la sección Wallet.
- Crea una API key (empieza por
tk_live_; se muestra una sola vez). - Llama a
POST /api/tolls/calculate(1 crédito por cálculo).
# Define TOLLS_API_KEY con tu clave; usa una clave única y persistente por cálculo.
export TOLLS_API_KEY='YOUR_TOLLS_API_KEY'
curl -X POST https://api.tolls.cargoffer.com/api/tolls/calculate \
-H "Authorization: Bearer $TOLLS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: route-estimate-001" \
-d '{
"origin": {"lat": 40.4168, "lng": -3.7038},
"destination": {"lat": 41.3874, "lng": 2.1686},
"vehicleType": "pesado_1"
}'
Los créditos solo se cobran si el cálculo se sirve. Si el motor falla, el crédito se reembolsa automáticamente. Una clave ya procesada devuelve 409 y no se cobra otra vez, pero la API no repite la respuesta anterior. Guarda la respuesta junto a la clave y usa una nueva para cada cálculo nuevo.
🔑 Autenticación
Autentica cada petición con Authorization: Bearer <token>. Puedes usar una API key o el JWT de sesión del dashboard.
| Método | Uso |
|---|---|
tk_live_… (API key) | Agentes, MCP, integraciones servidor-servidor. Hasta 10 keys por cuenta, revocables desde el dashboard. |
| JWT de sesión | El dashboard. POST /api/auth/login → accessToken (2 h) + refreshToken (30 d). |
Verifica cualquier token contra GET /api/auth/validate: responde sujeto, tipo y scopes. MCP: los clientes pueden usar el servidor oficial https://mcp.tolls.cargoffer.com/mcp (streamable HTTP, Bearer obligatorio en cada request).
🧭 Errores
| HTTP | Significado | Qué hacer |
|---|---|---|
| 400 | Petición inválida (coordenadas, vehicleType) | Corrige el body: origin/destination son objetos {lat,lng}; vehicleType ligero|pesado_1|pesado_2 |
| 401 | Token ausente o inválido | Regenera la API key o refresca el JWT |
| 402 | Saldo insuficiente | Recarga créditos o canjea un cupón; no se llamó al motor |
| 404 | Recurso o cupón inexistente | Revisa el código/path |
| 409 | Idempotency-Key o cupón ya usado | Genera una clave nueva para un cálculo nuevo |
| 429 | Límite de peticiones (demo) | Espera y reintenta con backoff |
| 502 | Motor de peajes no disponible | Reintenta; el crédito ya fue reembolsado |
| 503 | Monedero temporalmente no disponible | Reintenta en unos segundos (fail-closed) |
⏱️ Límites y demo
- Límites por separado según cómo te autentiques, para que un atasco anónimo no bloquee a los clientes: API key 200 req/min por clave, sesión del dashboard 300 req/min por IP, sin autenticar 50 req/min por IP. Al superarlos:
429con cabeceraRetry-After. - Demo
POST /api/demo/calculate: 5 req/min por IP y 500 cálculos/día de fondo compartido (429 al agotarse). Sin auth, sin coste. - Hasta 10 API keys activas por cuenta; revocar una libera la plaza.
GET /api/keys/limitspublica el tope vigente. - Cada cálculo servido consume 1 crédito y queda registrado en
GET /api/history.
🎟️ Cupones
Un cupón acredita créditos directamente en el monedero, sin pago: POST /api/wallet/redeem con {"code":"…"}. Cada cuenta puede canjear cada cupón una sola vez (409 si repite); los cupones pueden estar limitados a un email o a N redenciones totales.
🧩 Odoo
Para integrar Odoo, realiza la petición desde un módulo personalizado o un worker Python autorizado para llamadas HTTP. Conserva una Idempotency-Key por cálculo lógico y reutilízala solo al reintentar la misma operación:
El contexto y las variables de Server Actions dependen de la versión y configuración de Odoo. Este ejemplo es un patrón Python de integración; verifica la documentación oficial antes de ejecutarlo dentro de Odoo: documentación oficial de Server Actions (Odoo 19)
import os
import requests
# Lee un UUID guardado para este cálculo; reutilízalo solo en reintentos.
calculation_id = "persisted-uuid-for-this-calculation"
response = requests.post(
"https://api.tolls.cargoffer.com/api/tolls/calculate",
headers={
"Authorization": f"Bearer {os.environ['TOLLS_API_KEY']}",
"Content-Type": "application/json",
"Idempotency-Key": f"odoo-toll-{calculation_id}",
},
json={
"origin": {"lat": 40.4168, "lng": -3.7038},
"destination": {"lat": 41.3874, "lng": 2.1686},
"vehicleType": "pesado_1",
},
timeout=30,
)
response.raise_for_status()
tolls = response.json()Ejemplo Node.js (18+):
const apiKey = process.env.TOLLS_API_KEY;
const idempotencyKey = process.env.TOLLS_IDEMPOTENCY_KEY; // Persistir por cálculo lógico.
const response = await fetch('https://api.tolls.cargoffer.com/api/tolls/calculate', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify({
origin: { lat: 40.4168, lng: -3.7038 },
destination: { lat: 41.3874, lng: 2.1686 },
vehicleType: 'pesado_1',
}),
});
if (!response.ok) throw new Error(`Tolls API HTTP ${response.status}`);
const tolls = await response.json();
Una clave ya procesada devuelve 409: no vuelve a cobrar, pero la respuesta original no se reproduce. Guarda la respuesta junto a la clave y usa otra clave para un cálculo nuevo.
📜 Changelog
| Fecha | Cambio |
|---|---|
| 2026-10-29 | Cupones de monedero (/api/wallet/coupons, /api/wallet/redeem), GET /api/auth/validate, ledger idempotente y cabecera Idempotency-Key en /api/tolls/calculate (409 en reutilización). |
| 2026-09-04 | v1: auth, API keys, wallet + Stripe, proxy de cálculo, history, demo pública. |
Preguntas frecuentes
¿Cuántos créditos consume un cálculo?
Cada cálculo servido consume 1 crédito. Si falla el motor o rechaza la petición, el API reembolsa el crédito.
¿Qué ocurre al reutilizar una Idempotency-Key?
El API devuelve 409, sin un segundo cargo ni otra llamada al motor. No reproduce la respuesta original; guarda la respuesta junto con la clave.
¿Qué formato tienen las coordenadas?
Envía origin y destination como objetos con latitud y longitud decimales: {lat, lng}. El tipo de vehículo se envía en vehicleType.