RutaDocs

Recursos

Ejemplos

Ejemplos completos con curl y JavaScript (Node.js 18+, fetch nativo). Reemplazá RUTA_API por el dominio de tu courier.

curl: el ciclo completo en el entorno de prueba

Terminal
export RUTA_API='https://<tu-courier>'
export RUTA_API_KEY='ruta_test_…'

# Crear
ID=$(curl -s -X POST "$RUTA_API/api/v1/deliveries" \
  -H "Authorization: Bearer $RUTA_API_KEY" -H "Idempotency-Key: pedido-2001" -H "Content-Type: application/json" \
  -d '{"customerName":"Ana Pérez","address":"Av. Italia 1234","externalReference":"2001","amountToCollect":"850"}' \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')

# Corregir la dirección antes de que salga
curl -s -X PATCH "$RUTA_API/api/v1/deliveries/$ID" \
  -H "Authorization: Bearer $RUTA_API_KEY" -H "Content-Type: application/json" \
  -d '{"address":"Av. Italia 1234, apto 7"}'

# Simular el recorrido (sólo claves de prueba)
for action in ASSIGN PICK_UP START DELIVER SETTLE; do
  curl -s -X POST "$RUTA_API/api/v1/deliveries/$ID/simulate" \
    -H "Authorization: Bearer $RUTA_API_KEY" -H "Content-Type: application/json" \
    -d "{\"action\":\"$action\"}" > /dev/null
done

# Ver el resultado, el comprobante y la etiqueta
curl -s "$RUTA_API/api/v1/deliveries?externalReference=2001" -H "Authorization: Bearer $RUTA_API_KEY"
curl -s "$RUTA_API/api/v1/deliveries/$ID/proof" -H "Authorization: Bearer $RUTA_API_KEY"   # necesita proof:read
curl -s -o etiqueta.pdf "$RUTA_API/api/v1/deliveries/$ID/label" -H "Authorization: Bearer $RUTA_API_KEY"

JavaScript: un cliente mínimo con reintentos seguros

JavaScript
const API = process.env.RUTA_API
const KEY = process.env.RUTA_API_KEY

async function ruta(method, path, { body, idempotencyKey } = {}) {
  for (let attempt = 1; ; attempt++) {
    let response
    try {
      response = await fetch(`${API}${path}`, {
        method,
        headers: {
          Authorization: `Bearer ${KEY}`,
          ...(body ? { 'Content-Type': 'application/json' } : {}),
          ...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {}),
        },
        body: body ? JSON.stringify(body) : undefined,
        signal: AbortSignal.timeout(15_000),
      })
    } catch (error) {
      if (attempt >= 5) throw error // red caída: reintentar con la MISMA clave es seguro
      await new Promise(resolve => setTimeout(resolve, 500 * 2 ** attempt))
      continue
    }
    if (response.status === 429 || response.status >= 500) {
      if (attempt >= 5) throw new Error(`Ruta ${response.status}`)
      const wait = Number(response.headers.get('Retry-After') ?? 2 ** attempt)
      await new Promise(resolve => setTimeout(resolve, wait * 1000))
      continue
    }
    const text = await response.text()
    const json = text ? JSON.parse(text) : null
    if (!response.ok) {
      const error = new Error(json?.detail ?? `Ruta ${response.status}`)
      error.code = json?.code // decidí por code, no por el texto
      error.status = response.status
      throw error
    }
    return json
  }
}

// Un pedido de la tienda → una entrega. El número de pedido es la clave de idempotencia y la referencia.
export async function shipOrder(order) {
  try {
    return await ruta('POST', '/api/v1/deliveries', {
      idempotencyKey: `pedido-${order.number}`,
      body: {
        customerName: order.customer.name,
        address: order.shipping.address,
        recipientPhone: order.customer.phone ?? null,
        externalReference: String(order.number),
        amountToCollect: order.cashOnDelivery ? order.total.toFixed(2) : null,
      },
    })
  } catch (error) {
    if (error.code === 'EXTERNAL_REFERENCE_TAKEN') {
      const { deliveries } = await ruta('GET', `/api/v1/deliveries?externalReference=${encodeURIComponent(order.number)}`)
      return deliveries[0]
    }
    throw error
  }
}

// Todas las entregas, página por página.
export async function* allDeliveries() {
  let cursor = null
  do {
    const page = await ruta('GET', `/api/v1/deliveries?limit=100${cursor ? `&cursor=${cursor}` : ''}`)
    yield* page.deliveries
    cursor = page.nextCursor
  } while (cursor)
}

JavaScript: recibir avisos con Express

JavaScript
import express from 'express'
import { verifyRuta } from './verify-ruta.js' // la función de «Webhooks → Verificar la firma»

const app = express()
const seen = new Set() // en producción, una tabla con índice único por event id

app.post('/webhooks/ruta', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verifyRuta(process.env.RUTA_WEBHOOK_SECRET, req.get('Ruta-Signature') ?? '', req.body)) {
    return res.status(400).end()
  }
  const event = JSON.parse(req.body.toString('utf8'))
  res.status(204).end() // respondé enseguida y procesá después
  if (seen.has(event.id)) return
  seen.add(event.id)
  if (event.type === 'delivery.delivered') markOrderDelivered(event.data.externalReference)
  if (event.type === 'delivery.failed') notifyCustomer(event.data.externalReference, event.data.failureReasonCode)
})

app.listen(3000)

Postman e Insomnia

El contrato de la API está en openapi.json (OpenAPI 3.1, sólo /api/v1 y webhooks), con ejemplos en curl, JavaScript, Python y PHP.

  1. Descargá openapi.json (o copiá su dirección: https://<tu-courier>/docs/openapi.json).
  2. Postman: Import → elegí el archivo o pegá la dirección → Import. Se crea una colección con cada endpoint.
    Insomnia: Create → Import → el archivo o la dirección.
  3. En la colección, definí la variable baseUrl con https://<tu-courier> y en Authorization elegí Bearer Token con tu clave ruta_test_….
  4. Para crear entregas, agregá el encabezado Idempotency-Key con un valor nuevo por entrega (Postman: {{$guid}}).

Consejo

Empezá siempre con una clave de prueba: las entregas no llegan a ningún repartidor y no consumen cupo.

Ver en Markdown