Motify Developers Sandbox · api.motify.illari.ai

Pedir una carrera

Negociación estilo inDrive: el pasajero propone el precio, los conductores cercanos aceptan o contraofertan, y el pasajero elige. El pago es 100% directo (efectivo/Yape) — la plataforma nunca toca el dinero. Requiere el JWT del Flujo 1.

HTTP manda, MQTT avisa. Los comandos van por HTTP; las novedades (ofertas, estados, GPS del conductor) llegan en tiempo real por MQTT — la app NO hace polling. Suscripciones del pasajero: motify/pax/{userId}/inbox y, ya asignado, motify/ride/{rideId}/loc + motify/ride/{rideId}/events.

Secuencia completa

sequenceDiagram autonumber participant App as App (pasajero) participant API as Rides API participant MQTT as MQTT (IoT Core) participant Drv as Conductores cercanos App->>API: POST /v1/rides { rideId, pickup, dropoff, proposedFare } API->>Drv: sondeo → inbox de cada uno (vía MQTT) API-->>App: 201 { searchUntil, notifiedDrivers } Drv->>API: POST /rides/{id}/offers { accept | counter } API->>MQTT: pax/{userId}/inbox: oferta {driver, fare, expiresAt} MQTT-->>App: ofertas en vivo (60 s de vida c/u) App->>API: POST /rides/{id}/assign { driverId } API-->>App: 200 { agreedFare } · a los demás: request_closed Note over App,MQTT: la app se suscribe a ride/{id}/loc y ride/{id}/events Drv->>MQTT: GPS cada 4 s → ride/{id}/loc MQTT-->>App: posición del conductor en vivo Drv->>API: status: arriving → started → completed MQTT-->>App: cada transición llega por events/inbox App->>API: POST /rides/{id}/rating { stars, comment }

Paso a paso

1
Crear la solicitud. El rideId lo genera tu app (idempotencia); la tarifa va en céntimos.
curl -X POST https://api.motify.illari.ai/rides/v1/rides \
  -H "authorization: Bearer $JWT" -H "content-type: application/json" \
  -d '{"rideId":"c9k2mf3ab7",
       "pickup":  {"lat":-5.19449,"lng":-80.63282},
       "dropoff": {"lat":-5.18001,"lng":-80.62122},
       "proposedFare": 800}'

201 { "rideId":"c9k2mf3ab7", "status":"REQUESTED",
      "searchUntil":1788470000, "notifiedDrivers":["moto-1","moto-3"] }
Un pasajero solo puede tener UNA solicitud activa → segundo create da 409. Al abrir la app usa GET /v1/rides/active para retomar lo que haya quedado vivo.
2
Esperar ofertas (por MQTT, no polling). Cada oferta llega al inbox con 60 s de vida:
// motify/pax/{userId}/inbox
{ "type":"offer", "rideId":"c9k2mf3ab7", "offerType":"counter",
  "fare":1000, "expiresAt":1788470060,
  "driver": { "id":"moto-3", "rating":5.0, "fleet":"gremio-demo" } }
Si vence searchUntil (2 min) sin ofertas, ofrece "seguir buscando": POST /v1/rides/{id}/search re-sondea otros 2 minutos.
3
Elegir conductor. Cierra la negociación — exactamente un ganador (transacción anti-carrera):
curl -X POST .../v1/rides/c9k2mf3ab7/assign \
  -H "authorization: Bearer $JWT" -d '{"driverId":"moto-3"}'

200 { "rideId":"c9k2mf3ab7", "driverId":"moto-3", "agreedFare":1000 }
agreedFare es el precio del trato: muéstralo grande — es lo que el pasajero pagará EN MANO al conductor.
4
Seguir el viaje. Suscríbete a ride/{id}/loc (GPS cada ~4 s) y ride/{id}/events. El conductor mueve los estados: arriving (en camino) → started (a bordo) → completed. Cancelar sigue disponible para ambos — con conductor asignado exige motivo de la lista corta.
5
Calificar. Bidireccional, una vez por actor, solo en COMPLETED:
curl -X POST .../v1/rides/c9k2mf3ab7/rating \
  -H "authorization: Bearer $JWT" -d '{"stars":5,"comment":"excelente"}'

Reglas que tu app debe respetar

ReglaDetalle
Una solicitud activaCreate con otra viva → 409. Resuelve con GET /active (+ cancelar si corresponde).
Ciclo de búsqueda2 min (searchUntil). Vencido: pregunta al usuario si sigue buscando (re-sondeo) o cancela.
Vida de la oferta60 s (expiresAt) — píntala con cuenta regresiva; assign sobre oferta vencida → 409.
Assign perdedorSi otro pasajero-flujo ganó (raro) → 409; vuelve a la lista de ofertas.
CancelaciónEn REQUESTED: libre. Ya asignada: motivo obligatorio de la lista (pasajero_no_esta, cambio_de_opinion, comportamiento, falla_mecanica, seguridad, demora_excesiva, acuerdo_fuera_de_app).
Tarifa mínima100 céntimos (S/ 1.00).
ReconciliaciónAl reconectar: GET /active + GET /rides/{id}; lo vivo llega por MQTT.
ReciboGET /rides/{id}/route (~1 min post-viaje) para pintar el recorrido real.

Probar estos endpoints en la referencia interactiva →