{"openapi":"3.1.0","info":{"title":"Buyology Courier API","description":"REST API for the Buyology courier management service.\n\n**Roles**:\n- `COURIER` — JWT issued by this service after courier login\n- `ADMIN` / `COURIER_ADMIN` — Keycloak RSA JWT\n- `ECOMMERCE_SERVICE` — RSA JWT from the ecommerce backend\n\n**Key flows**:\n- Couriers record GPS pings via `POST /api/v1/couriers/{id}/locations`\n- Admin views all courier locations on a map via `GET /api/v1/couriers/map`\n- Deliveries are created asynchronously via RabbitMQ from the ecommerce service\n","contact":{"name":"Buyology Team","email":"firdovsirz@gmail.com"},"version":"1.0.0"},"servers":[{"url":"http://localhost:8081","description":"Local development"},{"url":"https://courier.buyology.com","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Deliveries","description":"Delivery order lifecycle management"},{"name":"Auth","description":"Courier authentication — login, token refresh, logout. Admin signup."},{"name":"Couriers","description":"Courier management and location tracking"},{"name":"Assignments","description":"Courier delivery assignment accept/reject"}],"paths":{"/api/v1/deliveries/{id}/status":{"post":{"tags":["Deliveries"],"summary":"Update delivery status — use for transitions that don't require photo evidence (e.g. COURIER_ACCEPTED → ARRIVED_AT_PICKUP, PICKED_UP → ON_THE_WAY, ON_THE_WAY → ARRIVED_AT_DESTINATION). For PICKED_UP use POST /{id}/actions/pickup-proof; for DELIVERED use POST /{id}/actions/deliver-proof.","operationId":"updateStatus","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeliveryStatusRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DeliveryOrderResponse"}}}}}},"patch":{"tags":["Deliveries"],"summary":"Update delivery status — use for transitions that don't require photo evidence (e.g. COURIER_ACCEPTED → ARRIVED_AT_PICKUP, PICKED_UP → ON_THE_WAY, ON_THE_WAY → ARRIVED_AT_DESTINATION). For PICKED_UP use POST /{id}/actions/pickup-proof; for DELIVERED use POST /{id}/actions/deliver-proof.","operationId":"updateStatus_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeliveryStatusRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DeliveryOrderResponse"}}}}}}},"/api/v1/deliveries/{id}/cancel":{"post":{"tags":["Deliveries"],"summary":"Cancel a delivery order — terminal action, cannot be undone","operationId":"cancel","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelDeliveryRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DeliveryOrderResponse"}}}}}}},"/api/v1/deliveries/{id}/actions/pickup-proof":{"post":{"tags":["Deliveries"],"summary":"Submit pickup proof photo — transitions ARRIVED_AT_PICKUP → PICKED_UP","operationId":"submitPickupProof","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"photoTakenAt","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"photo":{"type":"string","format":"binary"}},"required":["photo"]}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DeliveryProofResponse"}}}}}}},"/api/v1/deliveries/{id}/actions/fail":{"post":{"tags":["Deliveries"],"summary":"Report a failed delivery — transitions any in-progress status → FAILED","operationId":"failDelivery","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FailDeliveryRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DeliveryOrderResponse"}}}}}}},"/api/v1/deliveries/{id}/actions/deliver-proof":{"post":{"tags":["Deliveries"],"summary":"Submit delivery proof photo — transitions ARRIVED_AT_DESTINATION → DELIVERED","operationId":"submitDeliveryProof","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"deliveredTo","in":"query","required":false,"schema":{"type":"string"}},{"name":"photoTakenAt","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"photo":{"type":"string","format":"binary"}},"required":["photo"]}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DeliveryProofResponse"}}}}}}},"/api/v1/couriers":{"get":{"tags":["Couriers"],"summary":"List couriers with optional filters and pagination","operationId":"findAll","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["ACTIVE","OFFLINE","SUSPENDED"]}},{"name":"vehicleType","in":"query","required":false,"schema":{"type":"string","enum":["BICYCLE","FOOT","SCOOTER","CAR"]}},{"name":"isAvailable","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"pageable","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Pageable"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageCourierResponse"}}}}}},"post":{"tags":["Couriers"],"summary":"Register a new courier profile — multipart form (no credentials; use /api/auth/admin/couriers for full onboarding)","operationId":"create","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreateCourierRequest"},"profileImage":{"type":"string","format":"binary"},"drivingLicenceImage":{"type":"string","format":"binary"}},"required":["data"]}}}},"responses":{"201":{"description":"Created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CourierResponse"}}}}}}},"/api/v1/couriers/{id}/locations":{"get":{"tags":["Couriers"],"summary":"Get paginated location history within a time window (max 7 days)","operationId":"getLocationHistory","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"pageable","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Pageable"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageCourierLocationResponse"}}}}}},"post":{"tags":["Couriers"],"summary":"Record a GPS location ping for a courier","operationId":"recordLocation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordLocationRequest"}}},"required":true},"responses":{"201":{"description":"Created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CourierLocationResponse"}}}}}}},"/api/v1/couriers/push-token":{"post":{"tags":["Couriers"],"summary":"Register or update the courier's FCM push-notification token","operationId":"registerPushToken","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterPushTokenRequest"}}},"required":true},"responses":{"204":{"description":"No Content"}}}},"/api/v1/assignments/{assignmentId}/respond":{"post":{"tags":["Assignments"],"summary":"Accept or reject the assignment","operationId":"respond","parameters":[{"name":"assignmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignmentRespondRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AssignmentResponse"}}}}}}},"/api/auth/courier/refresh":{"post":{"tags":["Auth"],"summary":"Refresh access token","description":"Exchange a valid refresh token for a new access JWT.","operationId":"refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}}}}},"/api/auth/courier/logout":{"post":{"tags":["Auth"],"summary":"Logout","description":"Revoke the supplied refresh token. The access JWT remains valid until expiry — keep its TTL short (≤ 15 min).","operationId":"logout","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenRequest"}}},"required":true},"responses":{"204":{"description":"No Content"}}}},"/api/auth/courier/login":{"post":{"tags":["Auth"],"summary":"Courier login","description":"Authenticate with phone number and password. Returns a short-lived access JWT and a long-lived refresh token.","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CourierLoginRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}}}}},"/api/auth/admin/couriers":{"post":{"tags":["Auth"],"summary":"Register a new courier (admin only) — multipart form","description":"Creates the courier profile, credentials, and vehicle details in one transaction. Driving licence images are required when vehicleType is SCOOTER or CAR. Requires ROLE_COURIER_ADMIN or ROLE_ADMIN.","operationId":"signup","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CourierSignupRequest"},"profileImage":{"type":"string","format":"binary"},"vehicleRegistration":{"type":"string","format":"binary"},"drivingLicenceFront":{"type":"string","format":"binary"},"drivingLicenceBack":{"type":"string","format":"binary"}},"required":["data"]}}}},"responses":{"201":{"description":"Created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CourierSignupResponse"}}}}}}},"/api/v1/couriers/{id}":{"get":{"tags":["Couriers"],"summary":"Get courier by ID — includes profileImageUrl and drivingLicenceImageUrl","operationId":"findById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CourierResponse"}}}}}},"delete":{"tags":["Couriers"],"summary":"Soft-delete a courier (preserves historical data)","operationId":"delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}},"patch":{"tags":["Couriers"],"summary":"Partially update courier profile — multipart form","operationId":"update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/UpdateCourierRequest"},"profileImage":{"type":"string","format":"binary"},"drivingLicenceImage":{"type":"string","format":"binary"}},"required":["data"]}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CourierResponse"}}}}}}},"/api/v1/couriers/{id}/status":{"patch":{"tags":["Couriers"],"summary":"Update courier operational status (ACTIVE / OFFLINE / SUSPENDED)","operationId":"updateStatus_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCourierStatusRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CourierResponse"}}}}}}},"/api/v1/couriers/{id}/availability":{"patch":{"tags":["Couriers"],"summary":"Toggle courier availability for new deliveries","operationId":"updateAvailability","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAvailabilityRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CourierResponse"}}}}}}},"/api/v1/deliveries":{"get":{"tags":["Deliveries"],"summary":"List delivery orders, optionally filtered by status","operationId":"findAll_1","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["CREATED","COURIER_ASSIGNED","COURIER_ACCEPTED","ARRIVED_AT_PICKUP","PICKED_UP","ON_THE_WAY","ARRIVED_AT_DESTINATION","DELIVERED","FAILED","CANCELLED"]}},{"name":"pageable","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Pageable"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageDeliveryOrderResponse"}}}}}}},"/api/v1/deliveries/{id}":{"get":{"tags":["Deliveries"],"summary":"Get delivery order by ID","operationId":"findById_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DeliveryOrderResponse"}}}}}}},"/api/v1/deliveries/{id}/proof":{"get":{"tags":["Deliveries"],"summary":"Get the proof record (pickup + delivery photos) for a delivery","operationId":"getProof","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DeliveryProofResponse"}}}}}}},"/api/v1/deliveries/{id}/history":{"get":{"tags":["Deliveries"],"summary":"Get full status history for a delivery order","operationId":"getStatusHistory","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryStatusHistoryResponse"}}}}}}}},"/api/v1/deliveries/my-history":{"get":{"tags":["Deliveries"],"summary":"Full delivery history for the courier (all statuses). Pass ?status=DELIVERED to filter by a specific status.","operationId":"getMyHistory","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["CREATED","COURIER_ASSIGNED","COURIER_ACCEPTED","ARRIVED_AT_PICKUP","PICKED_UP","ON_THE_WAY","ARRIVED_AT_DESTINATION","DELIVERED","FAILED","CANCELLED"]}},{"name":"pageable","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Pageable"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageDeliveryOrderResponse"}}}}}}},"/api/v1/deliveries/my-deliveries":{"get":{"tags":["Deliveries"],"summary":"Get all active (non-terminal) deliveries assigned to the authenticated courier","operationId":"getMyDeliveries","parameters":[{"name":"pageable","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Pageable"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageDeliveryOrderResponse"}}}}}}},"/api/v1/couriers/{id}/locations/latest":{"get":{"tags":["Couriers"],"summary":"Get the most recent location of a courier","operationId":"getLatestLocation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CourierLocationResponse"}}}}}}},"/api/v1/couriers/map":{"get":{"tags":["Couriers"],"summary":"Get all couriers with their latest GPS location for map display","description":"Returns every non-deleted courier (filtered by optional params) paired with their most-recent location ping. Couriers that have never sent a ping have latestLocation = null. Designed for polling every 10 s from the admin dashboard map.","operationId":"getCouriersForMap","parameters":[{"name":"status","in":"query","description":"Filter by operational status","required":false,"schema":{"type":"string","enum":["ACTIVE","OFFLINE","SUSPENDED"]}},{"name":"vehicleType","in":"query","description":"Filter by vehicle type","required":false,"schema":{"type":"string","enum":["BICYCLE","FOOT","SCOOTER","CAR"]}},{"name":"isAvailable","in":"query","description":"Filter by availability","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CourierMapResponse"}}}}}}}},"/api/v1/assignments/{assignmentId}":{"get":{"tags":["Assignments"],"summary":"Get assignment details for the authenticated courier","operationId":"getAssignment","parameters":[{"name":"assignmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AssignmentResponse"}}}}}}},"/api/v1/assignments/my-pending":{"get":{"tags":["Assignments"],"summary":"Poll for a pending assignment — call on app start and after WebSocket reconnect","operationId":"getMyPendingAssignment","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AssignmentResponse"}}}}}}},"/api/deliveries/{deliveryId}/chat":{"get":{"tags":["chat-rest-controller"],"operationId":"getHistory","parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageChatMessageResponse"}}}}}}}},"components":{"schemas":{"UpdateDeliveryStatusRequest":{"type":"object","properties":{"status":{"type":"string","enum":["CREATED","COURIER_ASSIGNED","COURIER_ACCEPTED","ARRIVED_AT_PICKUP","PICKED_UP","ON_THE_WAY","ARRIVED_AT_DESTINATION","DELIVERED","FAILED","CANCELLED"]},"latitude":{"type":"number"},"longitude":{"type":"number"},"notes":{"type":"string"}},"required":["status"]},"DeliveryOrderResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ecommerceOrderId":{"type":"string","format":"uuid"},"ecommerceStoreId":{"type":"string","format":"uuid"},"customerName":{"type":"string"},"customerPhone":{"type":"string"},"customerEmail":{"type":"string"},"pickupAddress":{"type":"string"},"pickupLat":{"type":"number"},"pickupLng":{"type":"number"},"dropoffAddress":{"type":"string"},"dropoffLat":{"type":"number"},"dropoffLng":{"type":"number"},"packageSize":{"type":"string","enum":["SMALL","MEDIUM","LARGE","EXTRA_LARGE"]},"packageWeight":{"type":"number"},"deliveryFee":{"type":"number"},"priority":{"type":"string","enum":["STANDARD","EXPRESS"]},"status":{"type":"string","enum":["CREATED","COURIER_ASSIGNED","COURIER_ACCEPTED","ARRIVED_AT_PICKUP","PICKED_UP","ON_THE_WAY","ARRIVED_AT_DESTINATION","DELIVERED","FAILED","CANCELLED"]},"assignedCourierId":{"type":"string","format":"uuid"},"estimatedDeliveryTime":{"type":"string","format":"date-time"},"actualDeliveryTime":{"type":"string","format":"date-time"},"cancelledReason":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CancelDeliveryRequest":{"type":"object","properties":{"reason":{"type":"string","minLength":1}},"required":["reason"]},"DeliveryProofResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deliveryId":{"type":"string","format":"uuid"},"pickupImageUrl":{"type":"string"},"pickupPhotoTakenAt":{"type":"string","format":"date-time"},"imageUrl":{"type":"string"},"signatureUrl":{"type":"string"},"deliveredTo":{"type":"string"},"photoTakenAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"FailDeliveryRequest":{"type":"object","properties":{"reason":{"type":"string","maxLength":500,"minLength":0},"latitude":{"type":"number"},"longitude":{"type":"number"}},"required":["reason"]},"CreateCourierRequest":{"type":"object","properties":{"firstName":{"type":"string","maxLength":100,"minLength":0},"lastName":{"type":"string","maxLength":100,"minLength":0},"phone":{"type":"string","maxLength":30,"minLength":0},"email":{"type":"string","format":"email","maxLength":150,"minLength":0},"vehicleType":{"type":"string","enum":["BICYCLE","FOOT","SCOOTER","CAR"]}},"required":["firstName","lastName","phone","vehicleType"]},"CourierResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string"},"lastName":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"vehicleType":{"type":"string","enum":["BICYCLE","FOOT","SCOOTER","CAR"]},"status":{"type":"string","enum":["ACTIVE","OFFLINE","SUSPENDED"]},"isAvailable":{"type":"boolean"},"rating":{"type":"number"},"profileImageUrl":{"type":"string"},"drivingLicenceImageUrl":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"RecordLocationRequest":{"type":"object","properties":{"latitude":{"type":"number","maximum":90.0,"minimum":-90.0},"longitude":{"type":"number","maximum":180.0,"minimum":-180.0},"heading":{"type":"number","maximum":360.0,"minimum":0.0},"speed":{"type":"number","minimum":0.0},"accuracyMeters":{"type":"number","minimum":0.0},"recordedAt":{"type":"string","format":"date-time"}},"required":["latitude","longitude"]},"CourierLocationResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"courierId":{"type":"string","format":"uuid"},"latitude":{"type":"number"},"longitude":{"type":"number"},"heading":{"type":"number"},"speed":{"type":"number"},"accuracyMeters":{"type":"number"},"recordedAt":{"type":"string","format":"date-time"}}},"RegisterPushTokenRequest":{"type":"object","properties":{"fcmToken":{"type":"string","maxLength":512,"minLength":0}},"required":["fcmToken"]},"AssignmentRespondRequest":{"type":"object","properties":{"action":{"type":"string","enum":["ACCEPT","REJECT"]},"rejectionReason":{"type":"string"},"rejectionReasonValid":{"type":"boolean"}},"required":["action"]},"AssignmentResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deliveryId":{"type":"string","format":"uuid"},"courierId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["PENDING","ACCEPTED","REJECTED","TIMED_OUT","CANCELLED"]},"attemptNumber":{"type":"integer","format":"int32"},"assignedAt":{"type":"string","format":"date-time"},"acceptedAt":{"type":"string","format":"date-time"},"rejectedAt":{"type":"string","format":"date-time"},"rejectionReason":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"pickupAddress":{"type":"string"},"pickupLat":{"type":"number"},"pickupLng":{"type":"number"},"dropoffAddress":{"type":"string"},"dropoffLat":{"type":"number"},"dropoffLng":{"type":"number"}}},"RefreshTokenRequest":{"type":"object","properties":{"refreshToken":{"type":"string","minLength":1}},"required":["refreshToken"]},"AuthResponse":{"type":"object","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"expiresIn":{"type":"integer","format":"int64"},"courierId":{"type":"string","format":"uuid"}}},"CourierLoginRequest":{"type":"object","properties":{"phoneNumber":{"type":"string","maxLength":30,"minLength":0},"password":{"type":"string","maxLength":100,"minLength":0}},"required":["password","phoneNumber"]},"CourierSignupRequest":{"type":"object","properties":{"firstName":{"type":"string","maxLength":100,"minLength":0},"lastName":{"type":"string","maxLength":100,"minLength":0},"phone":{"type":"string","maxLength":30,"minLength":0},"email":{"type":"string","format":"email","maxLength":150,"minLength":0},"initialPassword":{"type":"string","maxLength":100,"minLength":8},"vehicleType":{"type":"string","enum":["BICYCLE","FOOT","SCOOTER","CAR"]},"vehicleMake":{"type":"string","maxLength":100,"minLength":0},"vehicleModel":{"type":"string","maxLength":100,"minLength":0},"vehicleYear":{"type":"integer","format":"int32","maximum":2100,"minimum":1900},"vehicleColor":{"type":"string","maxLength":50,"minLength":0},"licensePlate":{"type":"string","maxLength":50,"minLength":0},"drivingLicenseNumber":{"type":"string","maxLength":100,"minLength":0},"drivingLicenseExpiry":{"type":"string","format":"date"}},"required":["firstName","initialPassword","lastName","phone","vehicleType"]},"CourierSignupResponse":{"type":"object","properties":{"courierId":{"type":"string","format":"uuid"},"firstName":{"type":"string"},"lastName":{"type":"string"},"phone":{"type":"string"},"accountStatus":{"type":"string","enum":["PENDING_ACTIVATION","ACTIVE","LOCKED","SUSPENDED"]},"vehicleType":{"type":"string","enum":["BICYCLE","FOOT","SCOOTER","CAR"]},"requiresDrivingLicense":{"type":"boolean"}}},"UpdateCourierRequest":{"type":"object","properties":{"firstName":{"type":"string","maxLength":100,"minLength":0},"lastName":{"type":"string","maxLength":100,"minLength":0},"email":{"type":"string","format":"email","maxLength":150,"minLength":0},"vehicleType":{"type":"string","enum":["BICYCLE","FOOT","SCOOTER","CAR"]}}},"UpdateCourierStatusRequest":{"type":"object","properties":{"status":{"type":"string","enum":["ACTIVE","OFFLINE","SUSPENDED"]}},"required":["status"]},"UpdateAvailabilityRequest":{"type":"object","properties":{"available":{"type":"boolean"}},"required":["available"]},"Pageable":{"type":"object","properties":{"page":{"type":"integer","format":"int32","minimum":0},"size":{"type":"integer","format":"int32","minimum":1},"sort":{"type":"array","items":{"type":"string"}}}},"PageDeliveryOrderResponse":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"last":{"type":"boolean"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"first":{"type":"boolean"},"numberOfElements":{"type":"integer","format":"int32"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryOrderResponse"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"empty":{"type":"boolean"}}},"PageableObject":{"type":"object","properties":{"paged":{"type":"boolean"},"pageNumber":{"type":"integer","format":"int32"},"pageSize":{"type":"integer","format":"int32"},"unpaged":{"type":"boolean"},"offset":{"type":"integer","format":"int64"},"sort":{"$ref":"#/components/schemas/SortObject"}}},"SortObject":{"type":"object","properties":{"unsorted":{"type":"boolean"},"sorted":{"type":"boolean"},"empty":{"type":"boolean"}}},"DeliveryStatusHistoryResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["CREATED","COURIER_ASSIGNED","COURIER_ACCEPTED","ARRIVED_AT_PICKUP","PICKED_UP","ON_THE_WAY","ARRIVED_AT_DESTINATION","DELIVERED","FAILED","CANCELLED"]},"latitude":{"type":"number"},"longitude":{"type":"number"},"changedBy":{"type":"string"},"notes":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"PageCourierResponse":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"last":{"type":"boolean"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"first":{"type":"boolean"},"numberOfElements":{"type":"integer","format":"int32"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/CourierResponse"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"empty":{"type":"boolean"}}},"PageCourierLocationResponse":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"last":{"type":"boolean"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"first":{"type":"boolean"},"numberOfElements":{"type":"integer","format":"int32"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/CourierLocationResponse"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"empty":{"type":"boolean"}}},"CourierMapResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string"},"lastName":{"type":"string"},"phone":{"type":"string"},"vehicleType":{"type":"string","enum":["BICYCLE","FOOT","SCOOTER","CAR"]},"status":{"type":"string","enum":["ACTIVE","OFFLINE","SUSPENDED"]},"isAvailable":{"type":"boolean"},"rating":{"type":"number"},"profileImageUrl":{"type":"string"},"latestLocation":{"$ref":"#/components/schemas/LocationSnapshot"}}},"LocationSnapshot":{"type":"object","properties":{"latitude":{"type":"number"},"longitude":{"type":"number"},"heading":{"type":"number"},"speed":{"type":"number"},"accuracyMeters":{"type":"number"},"recordedAt":{"type":"string","format":"date-time"}}},"ChatMessageResponse":{"type":"object","properties":{"messageId":{"type":"string","format":"uuid"},"deliveryOrderId":{"type":"string","format":"uuid"},"ecommerceOrderId":{"type":"string","format":"uuid"},"senderId":{"type":"string","format":"uuid"},"senderType":{"type":"string","enum":["CUSTOMER","COURIER"]},"messageType":{"type":"string","enum":["TEXT","CALL_OFFER","CALL_ANSWER","CALL_ICE_CANDIDATE","CALL_END","CALL_REJECT"]},"content":{"type":"string"},"sentAt":{"type":"string","format":"date-time"},"deliveredAt":{"type":"string","format":"date-time"},"readAt":{"type":"string","format":"date-time"}}},"PageChatMessageResponse":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"last":{"type":"boolean"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"first":{"type":"boolean"},"numberOfElements":{"type":"integer","format":"int32"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessageResponse"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"empty":{"type":"boolean"}}}},"securitySchemes":{"bearerAuth":{"type":"http","description":"JWT — courier token from POST /api/v1/auth/signin, or Keycloak token for admin roles","name":"bearerAuth","scheme":"bearer","bearerFormat":"JWT"}}}}