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.
motify/pax/{userId}/inbox y, ya asignado,
motify/ride/{rideId}/loc + motify/ride/{rideId}/events.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"] }
409.
Al abrir la app usa GET /v1/rides/active para retomar lo que haya quedado vivo.// 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.
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.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.
COMPLETED:
curl -X POST .../v1/rides/c9k2mf3ab7/rating \
-H "authorization: Bearer $JWT" -d '{"stars":5,"comment":"excelente"}'
| Regla | Detalle |
|---|---|
| Una solicitud activa | Create con otra viva → 409. Resuelve con GET /active (+ cancelar si corresponde). |
| Ciclo de búsqueda | 2 min (searchUntil). Vencido: pregunta al usuario si sigue buscando (re-sondeo) o cancela. |
| Vida de la oferta | 60 s (expiresAt) — píntala con cuenta regresiva; assign sobre oferta vencida → 409. |
| Assign perdedor | Si otro pasajero-flujo ganó (raro) → 409; vuelve a la lista de ofertas. |
| Cancelación | En 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ínima | 100 céntimos (S/ 1.00). |
| Reconciliación | Al reconectar: GET /active + GET /rides/{id}; lo vivo llega por MQTT. |
| Recibo | GET /rides/{id}/route (~1 min post-viaje) para pintar el recorrido real. |