API Reference

Integra tu planta con Orderafy

Crea órdenes de traslado, recibe la confirmación de entrega y consulta el estado de cada unidad con su evidencia fotográfica. Todo por HTTPS con JSON.

URL base:https://orderafy.app/api/v1
API v1

Introducción

Orderafy gestiona el traslado de unidades entre plantas y distribuidores con evidencia fotográfica verificable. Esta API permite a tu sistema crear órdenes, recibir la confirmación de entrega y consultar el estado de cada unidad en todo momento.

Todas las respuestas son JSON. Los errores usan un formato uniforme con el campo error. La integración se hace por HTTPS con una API key por cliente; la app del operador y el portal usan sus propios esquemas de autenticación (ver Autenticación).

Ciclo de vida de una orden

La integración crea la orden sin operador (estado imported); la asignación la hace el dispatcher en el portal. El ciclo normal es:

importedImportada — creada por la API, sin operador asignado
assignedAsignada — el dispatcher asignó un operador
in_transitEn tránsito — el operador recibió la unidad y va en camino
deliveredEntregada — confirmada por webhook o por cierre en campo
on_holdDetenida — en pausa por el dispatcher
cancelledCancelada — no se puede confirmar entrega

Evidencia con candado

Cada recepción y entrega exige fotos verificables antes de cerrar la orden: el resumen de evidencia (receiptPhotos, deliveryPhotos, incidentPhotos, signedOrderPhoto) viaja en cada respuesta de estado.

Autenticación

La API usa tres esquemas según el tipo de integración. Cada endpoint indica cuál requiere.

X-API-Key

API key (X-API-Key)

Para los endpoints de integración (/orders, /webhooks/delivery). Se envía en la cabecera X-API-Key. La llave se entrega UNA sola vez al generarla (npm run api:key); si se pierde, se revoca y se genera otra.

Bearer

JWT del operador (Bearer)

Para los endpoints de la app del operador (/api/drivers/...). Se envía como Authorization: Bearer <token>. El operador del token debe coincidir con el de la ruta.

cookie

Sesión del portal (cookie)

Para los endpoints de monitoreo, reportes y administración (/api/ordenes/..., /api/reports/..., /api/admin/...). Usa la cookie de sesión del portal; el rol requerido (admin, staff o dealer) se indica por endpoint.

Integración

Endpoints para el sistema del cliente: crear órdenes, consultar estado y confirmar entregas. Autenticación con API key.

POST/orders

Crear una orden de traslado

Registra una orden de traslado con el número de orden del sistema del cliente. Si orderNumber ya existe responde 409 (la consulta de estado se hace por GET /orders/{orderNumber}). La orden se crea sin operador (estado imported); la asignación la hace el dispatcher en el portal.

Autenticación: API key

Petición · Ejemplo

JSON
{
  "orderNumber": "INT-2026-0831-001",
  "origin": "Planta Escobedo, Nuevo León",
  "destination": "Distribuidor International Monterrey, NL",
  "unitVIN": "3HCDZAPR9SL123456",
  "unitDescription": "Camión International HV 2026",
  "dealerName": "International Monterrey",
  "scheduledDate": "2026-08-31",
  "observations": "Entrega programada antes de las 12:00"
}

curl

bash
curl -X POST https://orderafy.app/api/v1/orders \
  -H "Content-Type: application/json" \
  -H "X-API-Key: TU_API_KEY" \
  -d '{
    "orderNumber": "INT-2026-0831-001",
    "origin": "Planta Escobedo, Nuevo León",
    "destination": "Distribuidor International Monterrey, NL",
    "unitVIN": "3HCDZAPR9SL123456",
    "unitDescription": "Camión International HV 2026",
    "dealerName": "International Monterrey",
    "scheduledDate": "2026-08-31",
    "observations": "Entrega programada antes de las 12:00"
  }'

Respuesta · Ejemplo

JSON
{
  "order": {
    "id": "42",
    "orderNumber": "INT-2026-0831-001",
    "unitVIN": "3HCDZAPR9SL123456",
    "unitDescription": "Camión International HV 2026",
    "origin": "Planta Escobedo, Nuevo León",
    "destination": "Distribuidor International Monterrey, NL",
    "dealerName": "International Monterrey",
    "status": "imported",
    "driver": null,
    "scheduledDate": "2026-08-31",
    "receivedAt": null,
    "deliveredAt": null,
    "dieselLiters": null,
    "observations": "Entrega programada antes de las 12:00",
    "createdAt": "2026-08-31T09:12:00-06:00",
    "updatedAt": "2026-08-31T09:12:00-06:00"
  },
  "evidence": {
    "receiptPhotos": 0,
    "deliveryPhotos": 0,
    "incidentPhotos": 0,
    "signedOrderPhoto": false
  },
  "incidents": []
}

Respuestas

201Orden creada (estado inicial y evidencia vacía)
400Campos obligatorios faltantes o formato inválido
401API key faltante o inválida
409Ya existe una orden con ese orderNumber
503Base de datos no disponible
GET/orders/{orderNumber}

Consultar el estado de una orden

Devuelve los datos de la orden, su estado, el operador asignado (si aplica), el resumen de evidencia fotográfica y las incidencias abiertas/resueltas. Es el endpoint principal de seguimiento para el sistema del cliente.

Autenticación: API key

Parámetros

orderNumber
path
string
Requerido
Número de orden, tal como se envió al crearla

curl

bash
curl https://orderafy.app/api/v1/orders/INT-2026-0831-001 \
  -H "X-API-Key: TU_API_KEY"

Respuesta · Ejemplo

JSON
{
  "order": {
    "id": "42",
    "orderNumber": "INT-2026-0831-001",
    "unitVIN": "3HCDZAPR9SL123456",
    "unitDescription": "Camión International HV 2026",
    "origin": "Planta Escobedo, Nuevo León",
    "destination": "Distribuidor International Monterrey, NL",
    "dealerName": "International Monterrey",
    "status": "in_transit",
    "driver": {
      "name": "Carlos Ramírez",
      "phone": "+52 81 1234 5678"
    },
    "scheduledDate": "2026-08-31",
    "receivedAt": "2026-08-31T10:05:00-06:00",
    "deliveredAt": null,
    "dieselLiters": 385,
    "observations": "Entrega programada antes de las 12:00",
    "createdAt": "2026-08-31T09:12:00-06:00",
    "updatedAt": "2026-08-31T10:05:00-06:00"
  },
  "evidence": {
    "receiptPhotos": 3,
    "deliveryPhotos": 4,
    "incidentPhotos": 0,
    "signedOrderPhoto": true
  },
  "incidents": []
}

Respuestas

200Estado completo de la orden
401API key faltante o inválida
404La orden no existe
503Base de datos no disponible
POST/webhooks/delivery

Confirmación de entrega (webhook)

El sistema del cliente notifica que la unidad llegó a su destino; Orderafy cierra la orden como delivered. Cada llamada queda registrada en la bitácora de webhooks (payload íntegro) para trazabilidad. Idempotente: si la orden ya estaba entregada responde 200 con alreadyDelivered: true sin cambios. Reintenta con backoff exponencial (1s, 2s, 4s…) ante 503 y 5xx; no reintentes ante 400/401/404/409.

Autenticación: API key

Petición · Ejemplo

JSON
{
  "orderNumber": "INT-2026-0831-001",
  "deliveredAt": "2026-08-31T16:45:00-06:00",
  "receivedBy": "Almacén de producto terminado",
  "reference": "GR-88213",
  "observations": "Unidad sin novedad"
}

curl

bash
curl -X POST https://orderafy.app/api/v1/webhooks/delivery \
  -H "Content-Type: application/json" \
  -H "X-API-Key: TU_API_KEY" \
  -d '{
    "orderNumber": "INT-2026-0831-001",
    "deliveredAt": "2026-08-31T16:45:00-06:00",
    "receivedBy": "Almacén de producto terminado",
    "reference": "GR-88213",
    "observations": "Unidad sin novedad"
  }'

Respuesta · Ejemplo

JSON
{
  "order": {
    "id": "42",
    "orderNumber": "INT-2026-0831-001",
    "status": "delivered",
    "deliveredAt": "2026-08-31T16:45:00-06:00"
  },
  "evidence": {
    "receiptPhotos": 3,
    "deliveryPhotos": 4,
    "incidentPhotos": 0,
    "signedOrderPhoto": true
  },
  "incidents": [],
  "alreadyDelivered": false
}

Respuestas

200Entrega confirmada (o ya estaba confirmada)
400Cuerpo inválido (orderNumber obligatorio, deliveredAt ISO-8601)
401API key faltante o inválida
404La orden no existe (el evento queda en bitácora)
409La orden está cancelada; no se puede confirmar entrega
503Base de datos no disponible

Telemetría

Configuración server-driven, consentimiento, ingesta de recorrido y eventos de manejo, y reportes de score y heatmap.

GET/api/config

Configuración server-driven para la app del operador

Devuelve los catálogos activos del cliente (secciones de foto, campos del vehículo e ítems de inspección) ordenados por sort_order. Autenticación dual: JWT del operador o sesión del portal.

Autenticación: JWT del operador

Parámetros

tenant
query
string
Opcional
Slug del cliente (por defecto el del portal)
default: cliente del portal
moment
query
string
Opcional
Filtra por momento (applies_to IN (momento, 'both')); omitir devuelve todos
receipt | delivery

curl

bash
curl https://orderafy.app/api/v1/api/config \
  -H "Authorization: Bearer JWT_DEL_CHOFER"

Respuesta · Ejemplo

JSON
{
  "tenant": { "id": "1", "name": "Orderafy" },
  "moment": null,
  "sections": [
    {
      "id": "1",
      "tenantId": "1",
      "code": "front",
      "title": "Frente (exterior)",
      "description": null,
      "appliesTo": "both",
      "required": true,
      "minPhotos": 1,
      "maxPhotos": 2,
      "sortOrder": 2,
      "active": true
    }
  ],
  "vehicleFields": [
    {
      "id": "1",
      "tenantId": "1",
      "code": "diesel_level",
      "label": "Nivel de diésel",
      "unit": "%",
      "required": true,
      "appliesTo": "both",
      "sortOrder": 1,
      "active": true
    }
  ],
  "inspectionItems": [
    {
      "id": "1",
      "tenantId": "1",
      "code": "scratches",
      "label": "Rayones",
      "category": "carrocería",
      "states": [{ "value": "minor", "label": "Daño menor" }],
      "requiresPhoto": true,
      "appliesTo": "both",
      "sortOrder": 1,
      "active": true
    }
  ]
}

Respuestas

200Catálogos del cliente
400moment inválido o cliente desactivado
401Sin autenticación (ni JWT de operador ni sesión de portal)
404Cliente no encontrado
GET/api/drivers/{driverId}/telemetria

Configuración de telemetría + consentimiento del operador

La app del operador lo consume al abrir: con la config arma el aviso de privacidad y el intervalo adaptativo del GPS (server-driven); con el consentimiento decide si puede encender el tracking. consent es null si el operador aún no ha aceptado el aviso.

Autenticación: JWT del operador

Parámetros

driverId
path
integer
Requerido
Id del operador (drivers.id); debe coincidir con el del token

Respuesta · Ejemplo

JSON
{
  "tenant": { "id": "1", "name": "Orderafy" },
  "config": {
    "tenantId": "1",
    "gpsTrackingEnabled": true,
    "gpsIntervalSec": 20,
    "gpsAdaptive": true,
    "driverEventsEnabled": true,
    "overspeedLimitKmh": 95,
    "appEventsEnabled": true,
    "consentRequired": true,
    "retentionDays": 90,
    "scoreWeights": { "hard_brake": 8, "hard_accel": 6, "sharp_curve": 10, "overspeed": 12 },
    "updatedAt": "2026-08-31T09:00:00-06:00"
  },
  "consent": {
    "id": "3",
    "driverId": "2",
    "version": "v1",
    "gpsOk": true,
    "behaviorOk": true,
    "analyticsOk": false,
    "acceptedAt": "2026-08-28T11:20:00-06:00"
  },
  "noticeVersion": "v1",
  "fetchedAt": "2026-08-31T09:12:00-06:00"
}

Respuestas

200Configuración + consentimiento
401Sin JWT válido
403El token no corresponde al operador de la ruta
503Base de datos no disponible
POST/api/drivers/{driverId}/tracks

Ingesta de puntos de recorrido (batch)

Idempotente por UNIQUE (order_id, device_ts): un reintento del mismo lote (mismo batchId) no duplica puntos. Validaciones: cada orden del batch pertenece al operador y está en tránsito; consentimiento vigente; lat/lng en rango; deviceTs no más de 5 min en el futuro. Se rechaza el batch completo si el consentimiento se revocó o la telemetría está desactivada.

Autenticación: JWT del operador

Parámetros

driverId
path
integer
Requerido
Id del operador

Petición · Ejemplo

JSON
{
  "batchId": "3f2a1c4e-9b7d-4e5a-8f0c-1d2e3f4a5b6c",
  "points": [
    {
      "orderId": 42,
      "lat": 25.7894,
      "lng": -100.2653,
      "speedKmh": 62,
      "heading": 214,
      "accuracyM": 4.2,
      "source": "gps",
      "deviceTs": "2026-08-31T14:05:10-06:00"
    }
  ]
}

Respuesta · Ejemplo

JSON
{
  "accepted": 30,
  "duplicates": 0
}

Respuestas

202Batch aceptado (aceptados + duplicados)
400Payload o punto inválido (orden no en tránsito, coordenadas fuera de rango, deviceTs futuro…)
401Sin JWT válido
403Token de otro operador, telemetría desactivada o consentimiento revocado
503Base de datos no disponible
POST/api/drivers/{driverId}/events

Ingesta de eventos de manejo (batch)

Eventos de comportamiento de manejo detectados por la app del operador (frenadas, aceleraciones, curvas, exceso de velocidad). Idempotente por UNIQUE (order_id, device_ts, type). Mismas validaciones que tracks: orden en tránsito, consentimiento vigente y type en el enum.

Autenticación: JWT del operador

Parámetros

driverId
path
integer
Requerido
Id del operador

Petición · Ejemplo

JSON
{
  "batchId": "3f2a1c4e-9b7d-4e5a-8f0c-1d2e3f4a5b6c",
  "events": [
    {
      "orderId": 42,
      "type": "hard_brake",
      "lat": 25.7894,
      "lng": -100.2653,
      "magnitude": 0.62,
      "deviceTs": "2026-08-31T14:22:41-06:00"
    }
  ]
}

Respuesta · Ejemplo

JSON
{
  "accepted": 30,
  "duplicates": 0
}

Respuestas

202Batch aceptado (aceptados + duplicados)
400Payload o evento inválido (orden no en tránsito, type fuera del enum, deviceTs futuro…)
401Sin JWT válido
403Token de otro operador, eventos desactivados o consentimiento de comportamiento revocado
503Base de datos no disponible
GET/api/ordenes/{id}/recorrido

Recorrido de una orden (polyline + estadísticas)

Mapa de recorrido: puntos ordenados por device_ts, distancia real (suma Haversine), duración, zonas de parada (speed < 5 km/h por > 2 min) y distancia estimada origen→destino. Rol admin/monitoreo (admin|staff|dealer; el dealer solo ve sus órdenes).

Autenticación: Sesión del portal

Parámetros

id
path
integer
Requerido
Id de la orden

Respuesta · Ejemplo

JSON
{
  "orden": {
    "id": "42",
    "orderNumber": "INT-2026-0831-001",
    "status": "in_transit",
    "origin": "Planta Escobedo, Nuevo León",
    "destination": "Distribuidor International Monterrey, NL",
    "dealerName": "International Monterrey",
    "unitVin": "3HCDZAPR9SL123456",
    "unitDescription": "Camión International HV 2026",
    "driverId": "2",
    "driverName": "Carlos Ramírez"
  },
  "points": [
    {
      "lat": 25.7894,
      "lng": -100.2653,
      "speedKmh": 62,
      "heading": 214,
      "accuracyM": 4.2,
      "source": "gps",
      "deviceTs": "2026-08-31T14:05:10-06:00"
    }
  ],
  "stats": {
    "points": 182,
    "distanceKm": 48.3,
    "durationSec": 5220,
    "startTs": "2026-08-31T12:40:00-06:00",
    "endTs": "2026-08-31T14:07:00-06:00",
    "stops": [
      {
        "lat": 25.7911,
        "lng": -100.2584,
        "startTs": "2026-08-31T13:15:00-06:00",
        "endTs": "2026-08-31T13:22:00-06:00",
        "durationSec": 420,
        "avgSpeedKmh": 0
      }
    ],
    "estimatedDistanceKm": null
  }
}

Respuestas

200Recorrido de la orden
400Id inválido
401Sin sesión de portal
404Orden no encontrada o fuera del alcance del dealer
503Base de datos no disponible
GET/api/ordenes/{id}/eventos

Eventos de manejo de una orden (con estado acknowledged)

Lista los eventos de comportamiento de manejo de una orden (frenadas, aceleraciones, curvas, exceso de velocidad) con el estado acknowledged para el monitoreo. Se ordenan por device_ts descendente. Rol admin/monitoreo.

Autenticación: Sesión del portal

Parámetros

id
path
integer
Requerido
Id de la orden

Respuesta · Ejemplo

JSON
{
  "orderId": 42,
  "orderNumber": "INT-2026-0831-001",
  "events": [
    {
      "id": "128",
      "orderId": 42,
      "driverId": 2,
      "driverName": "Carlos Ramírez",
      "type": "hard_brake",
      "lat": 25.7894,
      "lng": -100.2653,
      "magnitude": 0.62,
      "deviceTs": "2026-08-31T14:22:41-06:00",
      "receivedAt": "2026-08-31T14:22:42-06:00",
      "acknowledged": true
    }
  ],
  "total": 1
}

Respuestas

200Eventos de la orden
400Id inválido
401Sin sesión de portal
404Orden no encontrada o fuera del alcance del dealer
503Base de datos no disponible
POST/api/ordenes/{id}/eventos/{eventId}/ack

Confirmar o descartar un evento de manejo

El monitoreo confirma (acknowledged: true) o descarta (false) un evento de manejo de la orden. Rol admin/monitoreo (el dealer solo sobre sus órdenes).

Autenticación: Sesión del portal

Parámetros

id
path
integer
Requerido
Id de la orden
eventId
path
integer
Requerido
Id del evento de manejo

Petición · Ejemplo

JSON
{
  "acknowledged": true
}

Respuesta · Ejemplo

JSON
{
  "id": "128",
  "orderId": 42,
  "driverId": 2,
  "driverName": "Carlos Ramírez",
  "type": "hard_brake",
  "lat": 25.7894,
  "lng": -100.2653,
  "magnitude": 0.62,
  "deviceTs": "2026-08-31T14:22:41-06:00",
  "receivedAt": "2026-08-31T14:22:42-06:00",
  "acknowledged": true
}

Respuestas

200Evento actualizado
400Id o body inválido
401Sin sesión de portal
404Orden o evento no encontrado
503Base de datos no disponible
GET/api/reports/telemetria/score

Score de manejo 0–100 + tendencia semanal + modo de manejo

Score de manejo (patrón Geotab): max(0, 100 − Σ(peso × N/km) × 100), normalizado por 100 km con km reales de order_tracks. Pesos desde score_weights (defaults: hard_brake 8, hard_accel 6, sharp_curve 10, overspeed 12). Score null si km < 50 en el periodo (sin datos suficientes). Sin driverId devuelve el agregado de flota; el desglose por operador exige rol admin.

Autenticación: Sesión del portal

Parámetros

driverId
query
integer
Opcional
Desglose por operador (requiere rol admin)
from
query
string
Opcional
Inicio del periodo (ISO 8601)
to
query
string
Opcional
Fin del periodo (ISO 8601); default ahora

Respuesta · Ejemplo

JSON
{
  "driverId": null,
  "from": "2026-06-01T00:00:00-06:00",
  "to": "2026-08-31T23:59:59-06:00",
  "km": 4820.5,
  "events": { "hard_brake": 3, "hard_accel": 1, "sharp_curve": 0, "overspeed": 0 },
  "weights": { "hard_brake": 8, "hard_accel": 6, "sharp_curve": 10, "overspeed": 12 },
  "score": 92,
  "trend": [
    { "weekStart": "2026-08-03", "km": 610.2, "events": { "hard_brake": 1, "hard_accel": 0, "sharp_curve": 0, "overspeed": 0 }, "score": 97 },
    { "weekStart": "2026-08-10", "km": 655.8, "events": { "hard_brake": 2, "hard_accel": 1, "sharp_curve": 0, "overspeed": 0 }, "score": 94 }
  ],
  "drivingModes": {
    "urbano": { "segments": 24, "km": 320.1 },
    "mixto": { "segments": 18, "km": 890.4 },
    "carretera": { "segments": 9, "km": 3610.0 }
  }
}

Respuestas

200Score, tendencia y modos de manejo
400Parámetros inválidos
401Sin sesión de portal
403Desglose por operador sin rol admin
503Base de datos no disponible
GET/api/reports/telemetria/heatmap

Heatmap de actividad de recorrido

Puntos agregados por celda de ~4 decimales (≈ 11 m). Agregado por defecto (privacidad); el filtro por operador (desglose) exige rol admin. Sin from, el periodo por defecto son los últimos 90 días (retención).

Autenticación: Sesión del portal

Parámetros

driverId
query
integer
Opcional
Desglose por operador (requiere rol admin)
from
query
string
Opcional
Inicio del periodo (ISO 8601)
to
query
string
Opcional
Fin del periodo (ISO 8601); default ahora

Respuesta · Ejemplo

JSON
{
  "points": [
    { "lat": 25.7894, "lng": -100.2653, "count": 12, "intensity": 0.8 }
  ],
  "total": 240,
  "from": "2026-06-01T00:00:00-06:00",
  "to": "2026-08-31T23:59:59-06:00",
  "driverId": null
}

Respuestas

200Celdas agregadas
400Parámetros inválidos
401Sin sesión de portal
403Desglose por operador sin rol admin
503Base de datos no disponible

Catálogos

Administración de catálogos server-driven (secciones de foto, campos del vehículo, checklist de inspección) y configuración de telemetría. Rol admin.

GETPOST/api/admin/evidence-sections

Secciones de foto (listar / crear)

Catálogo server-driven de secciones de fotos de evidencia (recepción y entrega). GET lista incluyendo inactivas; POST crea con rol admin.

Autenticación: Sesión del portalRol admin

Parámetros

tenant_id
query
integer
Opcional
Filtra por cliente; omitir devuelve todos

Petición · Ejemplo

JSON
{
  "code": "front",
  "title": "Frente (exterior)",
  "description": null,
  "applies_to": "both",
  "required": true,
  "min_photos": 1,
  "max_photos": 2,
  "sort_order": 2,
  "active": true
}

Respuestas

200Secciones de foto (GET)
201Sección creada (POST)
400Payload inválido o cliente inválido/desactivado
403Se requiere rol admin
409Código duplicado para el cliente
PUTDELETE/api/admin/evidence-sections/{id}

Sección de foto por id (actualizar / borrar)

PUT actualiza (acepta campos parciales); DELETE borra. 409 si el código está en uso por órdenes existentes — en ese caso desactívala con active=false.

Autenticación: Sesión del portalRol admin

Parámetros

id
path
integer
Requerido
Id de la sección

Petición · Ejemplo

JSON
{
  "title": "Frente (exterior)",
  "active": false
}

Respuesta · Ejemplo

JSON
{
  "deleted": true
}

Respuestas

200Sección actualizada (PUT) o borrada (DELETE)
404Sección no existe
409Código en uso por órdenes (DELETE)
GETPOST/api/admin/inspection-items

Ítems de inspección (listar / crear)

Catálogo server-driven del checklist de inspección de la unidad. GET lista incluyendo inactivos; POST crea con rol admin.

Autenticación: Sesión del portalRol admin

Parámetros

tenant_id
query
integer
Opcional
Filtra por cliente; omitir devuelve todos

Petición · Ejemplo

JSON
{
  "code": "scratches",
  "label": "Rayones",
  "category": "carrocería",
  "states": [{ "value": "minor", "label": "Daño menor" }],
  "requires_photo": true,
  "applies_to": "both",
  "sort_order": 1,
  "active": true
}

Respuestas

200Ítems de inspección (GET)
201Ítem creado (POST)
400Payload inválido o cliente inválido/desactivado
403Se requiere rol admin
409Código duplicado para el cliente
PUTDELETE/api/admin/inspection-items/{id}

Ítem de inspección por id (actualizar / borrar)

PUT actualiza (acepta campos parciales); DELETE borra. 409 si el código está en uso por órdenes existentes — en ese caso desactívalo con active=false.

Autenticación: Sesión del portalRol admin

Parámetros

id
path
integer
Requerido
Id del ítem

Petición · Ejemplo

JSON
{
  "label": "Rayones",
  "active": false
}

Respuesta · Ejemplo

JSON
{
  "deleted": true
}

Respuestas

200Ítem actualizado (PUT) o borrado (DELETE)
404Ítem no existe
409Código en uso por órdenes (DELETE)
GETPOST/api/admin/vehicle-fields

Campos del vehículo (listar / crear)

Catálogo server-driven de campos de datos del vehículo (texto, número, select, fecha). GET lista incluyendo inactivos; POST crea con rol admin.

Autenticación: Sesión del portalRol admin

Parámetros

tenant_id
query
integer
Opcional
Filtra por cliente; omitir devuelve todos

Petición · Ejemplo

JSON
{
  "code": "diesel_level",
  "label": "Nivel de diésel",
  "field_type": "select",
  "unit": "%",
  "options": [{ "value": "low", "label": "Bajo" }, { "value": "full", "label": "Lleno" }],
  "required": true,
  "applies_to": "both",
  "sort_order": 1,
  "active": true
}

Respuestas

200Campos del vehículo (GET)
201Campo creado (POST)
400Payload inválido o cliente inválido/desactivado
403Se requiere rol admin
409Código duplicado para el cliente
PUTDELETE/api/admin/vehicle-fields/{id}

Campo del vehículo por id (actualizar / borrar)

PUT actualiza (acepta campos parciales); DELETE borra. 409 si el código está en uso por órdenes existentes — en ese caso desactívalo con active=false.

Autenticación: Sesión del portalRol admin

Parámetros

id
path
integer
Requerido
Id del campo

Petición · Ejemplo

JSON
{
  "label": "Nivel de diésel",
  "active": false
}

Respuesta · Ejemplo

JSON
{
  "deleted": true
}

Respuestas

200Campo actualizado (PUT) o borrado (DELETE)
404Campo no existe
409Código en uso por órdenes (DELETE)
GETPUT/api/admin/telemetria

Configuración de telemetría del cliente (rol admin)

GET devuelve la configuración del cliente; PUT la actualiza (actualización parcial, upsert si la fila no existe). score_weights se fusiona con los pesos vigentes.

Autenticación: Sesión del portalRol admin

Parámetros

tenant_id
query
integer
Opcional
Cliente; omitir = primer cliente activo

Petición · Ejemplo

JSON
{
  "gpsTrackingEnabled": true,
  "gpsIntervalSec": 20,
  "gpsAdaptive": true,
  "driverEventsEnabled": true,
  "overspeedLimitKmh": 95,
  "appEventsEnabled": true,
  "consentRequired": true,
  "retentionDays": 90,
  "scoreWeights": { "hard_brake": 8, "hard_accel": 6, "sharp_curve": 10, "overspeed": 12 }
}

Respuestas

200Configuración del cliente (GET/PUT)
400Payload inválido (PUT)
401Sin sesión de portal
403Se requiere rol admin
404Sin configuración para el cliente (GET)
503Base de datos no disponible

Salud

Endpoints operativos públicos para validar el enlace y obtener la especificación.

GET/health

Health check público

Verifica la conectividad con la API y su base de datos. Sin autenticación; útil para validar el enlace antes de integrar.

Autenticación: PúblicoPúblico

curl

bash
curl https://orderafy.app/api/v1/health

Respuesta · Ejemplo

JSON
{
  "status": "ok",
  "service": "orderafy-api-v1",
  "database": true,
  "time": "2026-08-31T16:00:00-06:00"
}

Respuestas

200API y base de datos disponibles
503API en pie pero base de datos no disponible
GET/openapi

Especificación OpenAPI 3.1 (YAML)

Este mismo documento, servido en texto plano. Puede pegarse en editor.swagger.io o importarse en Postman para generar el cliente.

Autenticación: PúblicoPúblico

curl

bash
curl https://orderafy.app/api/v1/openapi

Respuestas

200Documento OpenAPI en YAML

Agentes de IA — Servidor MCP

Conecta cualquier agente de IA (Claude, Codex, asistentes propios) a Orderafy con el servidor MCP: órdenes, operadores, incidencias, evidencia con candado, PDFs y estado del ambiente — autenticado con tu API key por tenant y ambiente. Escribir en producción siempre requiere confirmación explícita.

Descarga el servidor

orderafy-mcp-cliente.zip

Incluye: paquete Python (whl), guía de instalación para clientes y ejemplo de uso. Requiere Python ≥ 3.11 y tu API key de Orderafy.

Configuración

BASH
export ORDERAFY_API_TOKEN_PROD="ord_live_TU_TOKEN"
orderafy-mcp

Ambientes: dev, qa, demo, prod. Un token solo funciona en su ambiente. Solicita tu API key al equipo Azimutha.

Herramientas del servidor (13)

list_ordersÓrdenes con totales por estatus
get_order_detailOrden + unidades + evidencia + incidencias
check_order_pdf¿Checklist adjunto? Campos extraídos
reprocess_pdfRe-extrae direcciones/geo/unidad del PDF
assign_driverAsigna / reasigna / desasigna operador
update_order_statusCancela o pone en espera
request_reevidenceSolicita recaptura de evidencia
list_driversOperadores + orden activa + GPS
get_driver_locationÚltima posición GPS
list_incidentsIncidencias con filtros
get_evidenceProgreso, fotos con SHA-256, checklist
get_environment_statusSalud del ambiente
check_ocr_statusSalud del servicio OCR

Errores

Todos los errores usan el mismo formato: un objeto JSON con el campo error y un mensaje legible.

Formato de error

JSON
{
  "error": "No existe la orden 'INT-2026-0831-001'."
}

En /webhooks/delivery los reintentos son seguros (idempotente): ante 503 y 5xx reintenta con backoff; no reintentes ante 400/401/404/409.

Códigos de estado comunes

400Solicitud inválida: faltan campos obligatorios o el formato no es correcto
401Autenticación faltante o inválida (API key, JWT o sesión)
403Sin permisos: el rol no permite la operación
404Recurso no encontrado (orden, operador, catálogo o configuración)
409Conflicto de estado: duplicado, código en uso u orden cancelada
503Base de datos no disponible: reintenta con backoff exponencial (1s, 2s, 4s…)