{"openapi":"3.1.0","info":{"title":"Weloz API","version":"1.0.0","description":"\nAPI de logística e entregas da Weloz.\n\n## 🔐 Autenticação\n\nA API usa **Firebase Authentication** para login inicial e **JWT interno** para requisições subsequentes.\n\n### Fluxo de autenticação:\n1. Cliente faz login no Firebase (Google, Apple, Email)\n2. Cliente envia o `idToken` do Firebase para `POST /api/auth/firebase/exchange`\n3. API retorna `accessToken` (JWT, 15min) e `refreshToken` (30 dias)\n4. Cliente usa `accessToken` no header `Authorization: Bearer {token}`\n5. Quando expirar, usa `POST /api/auth/refresh` para renovar\n\n## 👥 Perfis de Usuário\n\nUm usuário pode ter múltiplos perfis/roles:\n- **SENDER** - Remetente (envia pacotes)\n- **RECIPIENT** - Destinatário (recebe pacotes)\n- **DRIVER** - Motorista (realiza entregas)\n- **ADMIN** - Administrador do sistema\n    "},"servers":[{"url":"http://localhost:3001","description":"Desenvolvimento"},{"url":"https://api.weloz.com.br","description":"Produção"}],"tags":[{"name":"Health","description":"Healthcheck e status do serviço"},{"name":"Public","description":"Rastreamento público sem autenticação"},{"name":"Auth","description":"Autenticação e gerenciamento de tokens"},{"name":"Users","description":"Gerenciamento de usuários e perfis"},{"name":"Notifications","description":"Inbox de notificações do usuário"},{"name":"Items","description":"Cadastro de itens para transporte"},{"name":"Deliveries","description":"Gerenciamento de entregas"},{"name":"Driver","description":"Endpoints para motoristas"},{"name":"Freight","description":"Cálculo de frete"},{"name":"Upload","description":"Upload de arquivos"},{"name":"Admin","description":"Endpoints administrativos"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"🔐 JWT obtido via `/api/auth/firebase/exchange`"},"firebaseAuth":{"type":"http","scheme":"bearer","bearerFormat":"Firebase ID Token","description":"🔥 Token ID do Firebase Authentication"}},"schemas":{"DriverPayoutAccountStatus":{"type":"object","required":["provider","status","canReceiveTransfers","actionRequired","requirements"],"properties":{"provider":{"type":"string","enum":["stripe"]},"status":{"type":"string","enum":["NOT_CREATED","ONBOARDING_PENDING","UNDER_REVIEW","READY","RESTRICTED","DISABLED"]},"canReceiveTransfers":{"type":"boolean"},"actionRequired":{"type":"boolean"},"statusReason":{"type":["string","null"]},"requirements":{"type":"array","items":{"type":"string"}},"lastSyncedAt":{"type":["string","null"],"format":"date-time"}}},"UserRole":{"type":"string","enum":["ADMIN","DRIVER","SENDER","RECIPIENT"],"description":"Papel/perfil do usuário no sistema"},"DeliveryStatus":{"type":"string","enum":["PENDING","ACCEPTED","IN_TRANSIT","DELIVERED","CANCELLED"],"description":"Status da entrega"},"VehicleType":{"type":"string","enum":["MOTORCYCLE","CAR","VAN","TRUCK"],"description":"Tipo de veículo"},"VehicleBodyCategory":{"type":"string","enum":["MOTORCYCLE","HATCH","SEDAN","SUV","VAN","TRUCK"],"description":"Categoria de carroceria para capacidade de porta-malas"},"VehicleCapacitySource":{"type":"string","enum":["CATALOG","CATEGORY_FALLBACK","MANUAL"],"description":"Origem da capacidade sugerida ou persistida"},"ProductType":{"type":"string","enum":["ELECTRONICS","CLOTHING","FOOD","DOCUMENTS","FURNITURE","AUTO_PARTS","BEAUTY","SPORTS","TOYS","BOOKS","MEDICINE","FRAGILE","OTHER"],"description":"Tipo de produto para transporte"},"ItemLabel":{"type":"string","enum":["NO_RESTRICTION","FRAGILE","KEEP_UPRIGHT","DO_NOT_STACK","TEMPERATURE_CTRL","HAZARDOUS","PERISHABLE","HIGH_VALUE","LIQUID","FLAMMABLE","HANDLE_WITH_CARE"],"description":"Etiquetas do item. HAZARDOUS e FLAMMABLE são proibidas. HIGH_VALUE (ou valor >= ITEM_HIGH_VALUE_THRESHOLD) exige motorista profissional verificado."},"ItemStatus":{"type":"string","enum":["DRAFT","PENDING","IN_DELIVERY","DELIVERED","CANCELLED"],"description":"Status do item cadastrado"},"DriverApprovalDocumentNormalizedType":{"type":"string","enum":["DRIVER_LICENSE_FRONT","DRIVER_LICENSE_BACK","SELFIE_WITH_DOCUMENT","DRIVER_LICENSE_COMBINED","VEHICLE_REGISTRATION","PROOF_OF_ADDRESS","PROFILE_PHOTO","INSURANCE","OTHER"],"description":"Tipo normalizado para análise documental no painel admin. DRIVER_LICENSE_COMBINED representa legado onde frente e verso chegaram em um único arquivo."},"DriverApprovalDocument":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string"},"normalizedType":{"$ref":"#/components/schemas/DriverApprovalDocumentNormalizedType"},"fileUrl":{"type":"string","format":"uri"},"fileName":{"type":["string","null"]},"uploadedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":["string","null"],"format":"date-time"}},"required":["id","type","normalizedType","fileUrl","uploadedAt"]},"PendingDriverApproval":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"approvalStatus":{"type":"string","enum":["PENDING_DOCUMENTS","PENDING_APPROVAL","APPROVED","REJECTED","PERMANENTLY_DENIED","SUSPENDED"]},"approvalNotes":{"type":["string","null"]},"reapplyAvailableAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"vehicleType":{"$ref":"#/components/schemas/VehicleType"},"vehiclePlate":{"type":["string","null"]},"vehicleModel":{"type":["string","null"]},"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"displayName":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}},"required":["id"]},"documents":{"type":"array","items":{"$ref":"#/components/schemas/DriverApprovalDocument"}}},"required":["id","approvalStatus","createdAt","vehicleType","user","documents"]},"User":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firebaseUid":{"type":"string"},"email":{"type":"string","format":"email"},"displayName":{"type":"string"},"phone":{"type":"string"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/UserRole"}},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"UserProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"displayName":{"type":"string"},"phone":{"type":"string"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/UserRole"}},"mobileRoles":{"type":"array","description":"Subset de roles voltadas ao app mobile. Exclui ADMIN e mantém apenas DRIVER, SENDER e RECIPIENT.","items":{"type":"string","enum":["DRIVER","SENDER","RECIPIENT"]}},"activeRole":{"allOf":[{"$ref":"#/components/schemas/UserRole"}],"nullable":true,"description":"Role ativa resolvida para a sessão atual. Vem do access token autenticado da requisição."},"driverProfile":{"$ref":"#/components/schemas/DriverProfile"},"addresses":{"type":"array","items":{"$ref":"#/components/schemas/Address"}},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}}},"DriverProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"vehicleType":{"$ref":"#/components/schemas/VehicleType"},"vehiclePlate":{"type":"string"},"vehicleBrand":{"type":"string","nullable":true},"vehicleModel":{"type":"string"},"vehicleYear":{"type":"integer"},"vehicleColor":{"type":"string"},"vehicleBodyCategory":{"allOf":[{"$ref":"#/components/schemas/VehicleBodyCategory"}],"nullable":true},"trunkLiters":{"type":"number","nullable":true},"maxWeightKg":{"type":"number","nullable":true},"capacitySource":{"allOf":[{"$ref":"#/components/schemas/VehicleCapacitySource"}],"nullable":true},"capacitySourceLabel":{"type":"string","nullable":true},"driverLicense":{"type":"string"},"licenseExpiry":{"type":"string","format":"date-time"},"currentLatitude":{"type":"number"},"currentLongitude":{"type":"number"},"isAvailable":{"type":"boolean"},"notificationRadiusKm":{"type":"integer","minimum":1,"maximum":30,"default":8},"isDeliveryNotificationPaused":{"type":"boolean","default":false},"notificationPausedAt":{"type":"string","format":"date-time","nullable":true},"totalDeliveries":{"type":"integer"},"completedDeliveries":{"type":"integer","description":"Quantidade de entregas com status DELIVERED. Score complementar de viagens bem-sucedidas; independente de avaliação e de totalDeliveries."},"averageRating":{"type":"number","nullable":true,"description":"Média das avaliações (1 a 5). null quando o motorista ainda não foi avaliado."},"ratingsCount":{"type":"integer","description":"Quantidade de avaliações recebidas. 0 quando ainda não há avaliações."},"isProfessionalVerified":{"type":"boolean","description":"Flag distinta da KYC básica; habilita cargas de alto valor"}}},"DriverNotificationPreferences":{"type":"object","required":["notificationRadiusKm","isDeliveryNotificationPaused","notificationPausedAt","updatedAt"],"properties":{"notificationRadiusKm":{"type":"integer","minimum":1,"maximum":30,"default":8},"isDeliveryNotificationPaused":{"type":"boolean","default":false},"notificationPausedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"}}},"DriverNotificationPreferencesUpdateRequest":{"type":"object","properties":{"notificationRadiusKm":{"type":"integer","minimum":1,"maximum":30},"isDeliveryNotificationPaused":{"type":"boolean"}},"additionalProperties":false,"description":"Envie pelo menos um campo para atualizar. notificationPausedAt e calculado pelo backend."},"Address":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string","description":"Ex: Casa, Trabalho"},"street":{"type":"string"},"number":{"type":"string"},"complement":{"type":"string"},"neighborhood":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zipCode":{"type":"string"},"country":{"type":"string","default":"BR"},"latitude":{"type":"number"},"longitude":{"type":"number"},"isDefault":{"type":"boolean"}}},"TokenResponse":{"type":"object","properties":{"accessToken":{"type":"string","description":"JWT de acesso (expira em 15 min)"},"refreshToken":{"type":"string","description":"Token para renovar acesso (30 dias)"},"expiresIn":{"type":"integer","description":"Segundos até expirar","example":900},"user":{"$ref":"#/components/schemas/UserProfile"}}},"Item":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"productType":{"$ref":"#/components/schemas/ProductType"},"description":{"type":"string"},"declaredValue":{"type":"number"},"height":{"type":"number","description":"Altura em cm"},"width":{"type":"number","description":"Largura em cm"},"length":{"type":"number","description":"Comprimento em cm"},"weight":{"type":"number","description":"Peso em kg"},"labels":{"type":"array","items":{"$ref":"#/components/schemas/ItemLabel"}},"status":{"$ref":"#/components/schemas/ItemStatus"},"photos":{"type":"array","items":{"$ref":"#/components/schemas/ItemPhoto"}},"documents":{"type":"array","items":{"$ref":"#/components/schemas/ItemDocument"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ItemPhoto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"filename":{"type":"string"},"mimeType":{"type":"string"},"size":{"type":"integer","description":"Tamanho em bytes"},"order":{"type":"integer"}}},"ItemDocument":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["invoice","receipt","other"]},"url":{"type":"string","format":"uri"},"filename":{"type":"string"},"mimeType":{"type":"string"},"size":{"type":"integer"}}},"ItemListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Item"}},"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"}}},"Delivery":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"senderId":{"type":"string","format":"uuid"},"recipientId":{"type":"string","format":"uuid"},"driverId":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/DeliveryStatus"},"pickupAddress":{"type":"string"},"pickupLatitude":{"type":"number"},"pickupLongitude":{"type":"number"},"pickupContactName":{"type":"string"},"pickupContactPhone":{"type":"string"},"deliveryAddress":{"type":"string"},"deliveryLatitude":{"type":"number"},"deliveryLongitude":{"type":"number"},"deliveryContactName":{"type":"string"},"deliveryContactPhone":{"type":"string"},"itemDescription":{"type":"string"},"itemWeight":{"type":"number"},"itemValue":{"type":"number"},"itemLength":{"type":"number"},"itemWidth":{"type":"number"},"itemHeight":{"type":"number"},"trackingCode":{"type":"string"},"notes":{"type":"string"},"item":{"type":"object","nullable":true,"description":"Item vinculado à entrega (quando existir)","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"photos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string"},"order":{"type":"integer"}}}}}},"requiresProfessionalDriver":{"type":"boolean","description":"True quando o item é HIGH_VALUE ou o valor declarado atinge ITEM_HIGH_VALUE_THRESHOLD"},"vehicleTypeNeeded":{"$ref":"#/components/schemas/VehicleType"},"distance":{"type":"number","description":"Distância em km"},"estimatedDuration":{"type":"integer","description":"Duração em minutos"},"basePrice":{"type":"number"},"weightPrice":{"type":"number"},"volumePrice":{"type":"number"},"estimatedPrice":{"type":"number"},"finalPrice":{"type":"number"},"scheduledPickupTime":{"type":"string","format":"date-time"},"pickupTime":{"type":"string","format":"date-time"},"deliveryTime":{"type":"string","format":"date-time"},"recipientConfirmedAt":{"type":"string","format":"date-time"},"estimatedArrivalAt":{"type":"string","format":"date-time"},"possiblyStuckAt":{"type":"string","format":"date-time","nullable":true,"description":"WELOZ-34: set when the driver appears stopped with the package (IN_TRANSIT)"},"stuckDetectedDriverId":{"type":"string","format":"uuid","nullable":true,"description":"Driver who had custody when the stuck signal was raised"},"stuckLatitude":{"type":"number","nullable":true},"stuckLongitude":{"type":"number","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"tripId":{"type":"string","format":"uuid"},"stopOrder":{"type":"integer","description":"Ordem de entrega no trajeto ativo"},"tripItinerary":{"$ref":"#/components/schemas/TripItinerary"},"verificationCodes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"purpose":{"type":"string","enum":["PICKUP","DELIVERY"]},"status":{"type":"string","enum":["ACTIVE","VERIFIED","EXPIRED","CANCELLED"]},"expiresAt":{"type":"string","format":"date-time"},"verifiedAt":{"type":"string","format":"date-time"}}}}}},"TrackingHistory":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/DeliveryStatus"},"latitude":{"type":"number"},"longitude":{"type":"number"},"notes":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"CreateRatingRequest":{"type":"object","required":["rating"],"properties":{"rating":{"type":"integer","minimum":1,"maximum":5,"description":"Nota inteira de 1 a 5 estrelas. A avaliação é opcional."},"comment":{"type":"string","description":"Campo opcional já existente no modelo; não é obrigatório."}}},"CreateRatingResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deliveryId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"Rating":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"rating":{"type":"integer","minimum":1,"maximum":5},"comment":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"displayName":{"type":"string"}}}}},"DeliveryListResponse":{"type":"object","required":["items","page","limit","total","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Delivery"}},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100},"total":{"type":"integer","minimum":0},"hasMore":{"type":"boolean"}}},"DeliveryCustodyRecord":{"type":"object","required":["id","deliveryId","driverId","startedAt"],"properties":{"id":{"type":"string","format":"uuid"},"deliveryId":{"type":"string","format":"uuid"},"driverId":{"type":"string","format":"uuid"},"startedAt":{"type":"string","format":"date-time"},"endedAt":{"type":"string","format":"date-time","nullable":true},"reason":{"type":"string","nullable":true,"description":"Motivo do encerramento do período de custódia"}}},"TransferDeliveryRequest":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":5,"maxLength":500,"description":"Motivo pelo qual o motorista atual não consegue continuar a entrega","example":"Imprevisto no trajeto. Não consigo concluir a entrega."}}},"RouteOffer":{"type":"object","description":"Oferta de encomenda compatível com o trajeto do motorista (matching por corredor, WELOZ-25)","properties":{"id":{"type":"string","format":"uuid"},"pickup":{"type":"object","properties":{"address":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"}},"required":["address","latitude","longitude"]},"dropoff":{"type":"object","properties":{"address":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"}},"required":["address","latitude","longitude"]},"item":{"type":"object","properties":{"description":{"type":"string"},"weightKg":{"type":"number"},"lengthCm":{"type":"number","nullable":true},"widthCm":{"type":"number","nullable":true},"heightCm":{"type":"number","nullable":true},"volumeLiters":{"type":"number"}},"required":["description","weightKg","volumeLiters"]},"driverEarnings":{"type":"object","properties":{"amount":{"type":"number","description":"Valor que o motorista receberá (BRL)"},"currency":{"type":"string","example":"BRL"}},"required":["amount","currency"]},"packageDistanceKm":{"type":"number","nullable":true},"detourKm":{"type":"number","nullable":true,"description":"Desvio do trajeto (soma das distâncias pickup/dropoff até a polyline)"},"vehicleTypeNeeded":{"$ref":"#/components/schemas/VehicleType","nullable":true}},"required":["id","pickup","dropoff","item","driverEarnings"]},"FreightCalculationRequest":{"type":"object","required":["pickupAddress","deliveryAddress","weight"],"properties":{"pickupAddress":{"type":"string","description":"Endereço de coleta"},"deliveryAddress":{"type":"string","description":"Endereço de entrega"},"weight":{"type":"number","description":"Peso em kg"},"length":{"type":"number","description":"Comprimento em cm"},"width":{"type":"number","description":"Largura em cm"},"height":{"type":"number","description":"Altura em cm"},"declaredValue":{"type":"number","description":"Valor declarado"},"vehicleType":{"$ref":"#/components/schemas/VehicleType"}}},"FreightCalculationResponse":{"type":"object","properties":{"distance":{"type":"number","description":"Distância em km"},"estimatedDuration":{"type":"integer","description":"Duração em minutos"},"basePrice":{"type":"number"},"weightPrice":{"type":"number"},"volumePrice":{"type":"number"},"totalPrice":{"type":"number"},"vehicleType":{"$ref":"#/components/schemas/VehicleType"}}},"Error":{"type":"object","properties":{"error":{"type":"string","description":"Código do erro (fonte única: domain/constants.ts)","enum":["UNAUTHORIZED","INVALID_TOKEN","EMAIL_NOT_VERIFIED","ACCOUNT_LINK_REQUIRED","TOKEN_EXPIRED","FORBIDDEN","USER_NOT_FOUND","USER_ALREADY_EXISTS","USER_INACTIVE","MEMBERSHIP_NOT_FOUND","INVALID_REQUEST","MISSING_REQUIRED_FIELDS","INVALID_FORMAT","INVALID_ROLE","NOT_FOUND","DELIVERY_NOT_FOUND","DELIVERY_ALREADY_ACCEPTED","DELIVERY_PAYMENT_NOT_AUTHORIZED","DELIVERY_PAYMENT_AUTHORIZATION_EXPIRED","DELIVERY_CANNOT_BE_CANCELLED","DELIVERY_CANNOT_BE_TRANSFERRED","DELIVERY_NOT_AVAILABLE_FOR_HANDOFF","DRIVER_CANNOT_REASSUME_TRANSFER","DELIVERY_ALREADY_CONFIRMED","DELIVERY_CANNOT_BE_CONFIRMED","DELIVERY_PROOF_REQUIRED","DELIVERY_VERIFICATION_CODE_REQUIRED","INVALID_DELIVERY_VERIFICATION_CODE","DELIVERY_VERIFICATION_CODE_EXPIRED","REVERSE_DELIVERY_NOT_FOUND","INVALID_DELIVERY_STATUS","INVALID_STATUS_TRANSITION","DRIVER_NOT_FOUND","DRIVER_NOT_AVAILABLE","DRIVER_PROFILE_NOT_FOUND","DRIVER_ROUTE_NOT_FOUND","DRIVER_LOCATION_REQUIRED","TRIP_ALREADY_ACTIVE","TRIP_NOT_FOUND","VEHICLE_CAPACITY_UNAVAILABLE","ACTIVE_TRIP_REQUIRED","CAPACITY_EXCEEDED","TIER_ITEM_LIMIT_EXCEEDED","DRIVER_PAYOUT_ACCOUNT_INCOMPLETE","RATING_ALREADY_EXISTS","PAYMENT_NOT_FOUND","PAYOUT_NOT_FOUND","INCIDENT_NOT_FOUND","CHECKOUT_SESSION_NOT_FOUND","QUOTE_NOT_FOUND","QUOTE_EXPIRED","QUOTE_ALREADY_USED","ITEM_NOT_FOUND","ITEM_ALREADY_IN_DELIVERY","PROHIBITED_ITEM","DRIVER_NOT_PROFESSIONALLY_VERIFIED","DRIVER_NOT_APPROVED","ETA_NOT_AVAILABLE","INTERNAL_ERROR","CONFLICT","SERVICE_UNAVAILABLE"]},"message":{"type":"string","description":"Mensagem de erro"},"details":{"type":"object","additionalProperties":true,"description":"Detalhes adicionais do erro"}},"required":["error","message"]},"ValidationError":{"type":"object","properties":{"error":{"type":"string","enum":["INVALID_REQUEST"],"example":"INVALID_REQUEST"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"type":"string"}},"message":{"type":"string"}}}}}},"City":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"São Paulo"},"state":{"type":"string","minLength":2,"maxLength":2,"example":"SP","description":"UF (sigla de 2 letras maiúsculas)"},"ibgeCode":{"type":"string","nullable":true,"example":"3550308","description":"Código IBGE de 7 dígitos (opcional)"},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","state","isActive","createdAt","updatedAt"]},"CreateCityRequest":{"type":"object","required":["name","state"],"properties":{"name":{"type":"string","minLength":2,"maxLength":120},"state":{"type":"string","minLength":2,"maxLength":2},"ibgeCode":{"type":"string","pattern":"^\\d{7}$","nullable":true},"isActive":{"type":"boolean","default":true}}},"UpdateCityRequest":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"state":{"type":"string","minLength":2,"maxLength":2},"ibgeCode":{"type":"string","pattern":"^\\d{7}$","nullable":true},"isActive":{"type":"boolean"}}},"CityListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/City"}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"totalPages":{"type":"integer"}},"required":["items","total","page","limit","totalPages"]},"CityPricing":{"type":"object","properties":{"id":{"type":"string"},"cityId":{"type":"string"},"pricePerKmCents":{"type":"integer","minimum":1,"description":"Valor por km rodado em centavos"},"minFareCents":{"type":"integer","minimum":0,"description":"Tarifa mínima em centavos"},"baseFareCents":{"type":"integer","minimum":0,"description":"Tarifa fixa de bandeirada em centavos"},"driverShareBps":{"type":"integer","minimum":0,"maximum":10000,"description":"Percentual repassado ao motorista em basis points (8000 = 80%)"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","cityId","pricePerKmCents","minFareCents","baseFareCents","driverShareBps","createdAt","updatedAt"]},"PricingSettings":{"type":"object","properties":{"motorcyclePricePerKm":{"type":"number","example":1.5},"carPricePerKm":{"type":"number","example":2},"vanPricePerKm":{"type":"number","example":3},"truckPricePerKm":{"type":"number","example":4.5},"platformFeeBps":{"type":"integer","minimum":0,"maximum":10000,"example":2000},"insuranceRate":{"type":"number","example":0.02},"isDefault":{"type":"boolean"}},"required":["motorcyclePricePerKm","carPricePerKm","vanPricePerKm","truckPricePerKm","platformFeeBps","insuranceRate","isDefault"]},"UpsertCityPricingRequest":{"type":"object","required":["pricePerKmCents"],"properties":{"pricePerKmCents":{"type":"integer","minimum":1},"minFareCents":{"type":"integer","minimum":0},"baseFareCents":{"type":"integer","minimum":0},"driverShareBps":{"type":"integer","minimum":0,"maximum":10000}}},"DeliveryRecipientRejection":{"type":"object","properties":{"id":{"type":"string"},"deliveryId":{"type":"string","format":"uuid"},"rejectedBy":{"type":"string"},"reason":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","deliveryId","rejectedBy","createdAt"]},"DeliveryDriverRejection":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deliveryId":{"type":"string","format":"uuid"},"driverId":{"type":"string","format":"uuid"},"reason":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","deliveryId","driverId","reason","createdAt","updatedAt"]},"DeliveryRescheduleRequest":{"type":"object","properties":{"id":{"type":"string"},"deliveryId":{"type":"string","format":"uuid"},"requestedBy":{"type":"string"},"proposedTime":{"type":"string","format":"date-time"},"reason":{"type":"string","nullable":true},"status":{"type":"string","enum":["PENDING","APPROVED","REJECTED","CANCELLED"]},"decidedBy":{"type":"string","nullable":true},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decisionNote":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","deliveryId","requestedBy","proposedTime","status","createdAt","updatedAt"]},"DeliveryAddressChange":{"type":"object","properties":{"id":{"type":"string"},"deliveryId":{"type":"string","format":"uuid"},"requestedBy":{"type":"string"},"proposedAddress":{"type":"string"},"proposedLatitude":{"type":"number"},"proposedLongitude":{"type":"number"},"reason":{"type":"string","nullable":true},"status":{"type":"string","enum":["PENDING","APPROVED","REJECTED","CANCELLED"]},"decidedBy":{"type":"string","nullable":true},"decidedAt":{"type":"string","format":"date-time","nullable":true},"decisionNote":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","deliveryId","requestedBy","proposedAddress","proposedLatitude","proposedLongitude","status","createdAt","updatedAt"]},"DeliveryAddressChangeListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryAddressChange"}}},"required":["items"]},"DeliveryRescheduleRequestListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryRescheduleRequest"}}},"required":["items"]},"VehicleModelCapacity":{"type":"object","properties":{"id":{"type":"string"},"brand":{"type":"string"},"model":{"type":"string"},"yearStart":{"type":"integer","nullable":true},"yearEnd":{"type":"integer","nullable":true},"bodyCategory":{"$ref":"#/components/schemas/VehicleBodyCategory"},"trunkLiters":{"type":"number","nullable":true},"maxWeightKg":{"type":"number","nullable":true},"source":{"type":"string","nullable":true},"sourceUrl":{"type":"string","nullable":true},"confidence":{"type":"string","nullable":true},"isActive":{"type":"boolean"}}},"VehicleCategoryCapacity":{"type":"object","properties":{"id":{"type":"string"},"bodyCategory":{"$ref":"#/components/schemas/VehicleBodyCategory"},"trunkLiters":{"type":"number","nullable":true},"maxWeightKg":{"type":"number","nullable":true}}},"SuggestVehicleCapacityRequest":{"type":"object","required":["vehicleType"],"properties":{"plate":{"type":"string"},"vehicleType":{"$ref":"#/components/schemas/VehicleType"},"brand":{"type":"string"},"model":{"type":"string"},"year":{"type":"integer"},"bodyCategory":{"$ref":"#/components/schemas/VehicleBodyCategory"},"trunkLiters":{"type":"number"},"maxWeightKg":{"type":"number"}}},"SuggestVehicleCapacityResponse":{"type":"object","properties":{"brand":{"type":"string","nullable":true},"model":{"type":"string","nullable":true},"year":{"type":"integer","nullable":true},"color":{"type":"string","nullable":true},"bodyCategory":{"allOf":[{"$ref":"#/components/schemas/VehicleBodyCategory"}],"nullable":true},"trunkLiters":{"type":"number","nullable":true},"maxWeightKg":{"type":"number","nullable":true},"source":{"allOf":[{"$ref":"#/components/schemas/VehicleCapacitySource"}],"nullable":true},"sourceLabel":{"type":"string","nullable":true},"sourceUrl":{"type":"string","nullable":true},"needsManualDefinition":{"type":"boolean"},"isEstimate":{"type":"boolean"},"plateLookupUsed":{"type":"boolean"},"plateLookupProvider":{"type":"string","nullable":true},"matchedCatalogId":{"type":"string","nullable":true},"message":{"type":"string"}}},"CreateVehicleModelCapacityRequest":{"type":"object","required":["brand","model","bodyCategory"],"properties":{"brand":{"type":"string"},"model":{"type":"string"},"yearStart":{"type":"integer","nullable":true},"yearEnd":{"type":"integer","nullable":true},"bodyCategory":{"$ref":"#/components/schemas/VehicleBodyCategory"},"trunkLiters":{"type":"number","nullable":true},"maxWeightKg":{"type":"number","nullable":true},"source":{"type":"string","nullable":true},"sourceUrl":{"type":"string","nullable":true},"confidence":{"type":"string","nullable":true},"isActive":{"type":"boolean"}}},"UpdateVehicleModelCapacityRequest":{"type":"object","properties":{"brand":{"type":"string"},"model":{"type":"string"},"yearStart":{"type":"integer","nullable":true},"yearEnd":{"type":"integer","nullable":true},"bodyCategory":{"$ref":"#/components/schemas/VehicleBodyCategory"},"trunkLiters":{"type":"number","nullable":true},"maxWeightKg":{"type":"number","nullable":true},"source":{"type":"string","nullable":true},"sourceUrl":{"type":"string","nullable":true},"confidence":{"type":"string","nullable":true},"isActive":{"type":"boolean"}}},"VehicleModelCapacityListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/VehicleModelCapacity"}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"totalPages":{"type":"integer"}}},"UpsertVehicleCategoryCapacityRequest":{"type":"object","properties":{"trunkLiters":{"type":"number","nullable":true},"maxWeightKg":{"type":"number","nullable":true}}},"OverrideDriverVehicleCapacityRequest":{"type":"object","properties":{"trunkLiters":{"type":"number","nullable":true},"maxWeightKg":{"type":"number","nullable":true},"bodyCategory":{"$ref":"#/components/schemas/VehicleBodyCategory"},"brand":{"type":"string"},"model":{"type":"string"},"year":{"type":"integer","nullable":true}}},"TripStop":{"type":"object","properties":{"sequence":{"type":"integer"},"type":{"type":"string","enum":["PICKUP","DROPOFF"]},"deliveryId":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"address":{"type":"string"},"estimatedArrivalAt":{"type":"string","format":"date-time"},"legDurationMinutes":{"type":"integer"}}},"TripItinerary":{"type":"object","description":"Trajeto com N entregas, capacidade restante e paradas recalculadas a cada aceite.","properties":{"tripId":{"type":"string"},"remainingCapacity":{"type":"object","properties":{"weightKg":{"type":"number"},"volumeLiters":{"type":"number"},"items":{"type":"integer"},"itemLimit":{"type":"integer"}}},"stops":{"type":"array","items":{"$ref":"#/components/schemas/TripStop"}},"deliveries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"$ref":"#/components/schemas/DeliveryStatus"},"stopOrder":{"type":"integer","nullable":true},"estimatedArrivalAt":{"type":"string","format":"date-time","nullable":true}}}}}},"NotificationType":{"type":"string","enum":["DELIVERY_ACCEPTED","DELIVERY_CANCELLED_BY_DRIVER","DELIVERY_WAITING_AT_PICKUP","DELIVERY_IN_TRANSIT","DELIVERY_COMPLETED","PAYMENT_CAPTURED","PAYOUT_SCHEDULED","PAYOUT_PAID","INCIDENT_UPDATED","DRIVER_APPROVED","DRIVER_REJECTED","SYSTEM"]},"PushToken":{"type":"object","required":["id","userId","token","isActive","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"token":{"type":"string"},"platform":{"type":"string","enum":["ios","android","web"],"nullable":true},"deviceId":{"type":"string","nullable":true},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"RegisterPushTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","minLength":20},"platform":{"type":"string","enum":["ios","android","web"]},"deviceId":{"type":"string","maxLength":100}}},"DeactivatePushTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","minLength":20}}},"Notification":{"type":"object","required":["id","userId","type","title","body","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/NotificationType"},"title":{"type":"string"},"body":{"type":"string"},"data":{"type":"object","additionalProperties":true,"nullable":true},"readAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"NotificationListResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}},"pagination":{"type":"object","required":["page","limit","total","unreadCount"],"properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"unreadCount":{"type":"integer"}}}}}}},"paths":{"/api/driver/identity-verifications":{"post":{"operationId":"driverStartIdentityVerification","tags":["Identity verification"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Estado da verificação de identidade"}}}},"/api/driver/identity-verifications/current":{"get":{"operationId":"driverGetCurrentIdentityVerification","tags":["Identity verification"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Estado da verificação de identidade"},"204":{"description":"Ainda não iniciada"}}}},"/api/driver/identity-verifications/current/submit":{"post":{"operationId":"driverSubmitIdentityVerification","tags":["Identity verification"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Estado da verificação de identidade"}}}},"/api/driver/identity-verifications/current/retry":{"post":{"operationId":"driverRetryIdentityVerification","tags":["Identity verification"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Estado da verificação de identidade"}}}},"/api/admin/identity-verifications":{"get":{"operationId":"adminListIdentityVerifications","tags":["Identity verification"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"provider","in":"query","schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Verificações mais recentes"}}}},"/api/admin/identity-verifications/{verificationId}":{"get":{"operationId":"adminGetIdentityVerification","tags":["Identity verification"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"verificationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detalhe, checks e auditoria da verificação"},"404":{"description":"Verificação não encontrada"}}}},"/api/admin/identity-verifications/{verificationId}/approve":{"post":{"operationId":"adminApproveIdentityVerification","tags":["Identity verification"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"verificationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Estado da verificação de identidade"}}}},"/api/admin/identity-verifications/{verificationId}/reject":{"post":{"operationId":"adminRejectIdentityVerification","tags":["Identity verification"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"verificationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Estado da verificação de identidade"}}}},"/api/admin/identity-verifications/{verificationId}/request-recapture":{"post":{"operationId":"adminRequestIdentityRecapture","tags":["Identity verification"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"verificationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Estado da verificação de identidade"}}}},"/api/identity-verification/webhooks/unico":{"post":{"operationId":"receiveUnicoIdentityVerificationWebhook","tags":["Identity verification"],"responses":{"204":{"description":"Evento processado"},"401":{"description":"Chave inválida"}}}},"/api/places/autocomplete":{"get":{"operationId":"placesAutocomplete","summary":"Autocomplete de lugares","tags":["Places"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2}},{"name":"lat","in":"query","required":false,"schema":{"type":"number"}},{"name":"lng","in":"query","required":false,"schema":{"type":"number"}},{"name":"sessionToken","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sugestões de lugares"},"401":{"description":"Não autenticado"}}}},"/api/places/directions":{"get":{"operationId":"placesDrivingDirections","summary":"Trajeto rodoviário entre dois pontos","tags":["Places"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"originLat","in":"query","required":true,"schema":{"type":"number"}},{"name":"originLng","in":"query","required":true,"schema":{"type":"number"}},{"name":"destinationLat","in":"query","required":true,"schema":{"type":"number"}},{"name":"destinationLng","in":"query","required":true,"schema":{"type":"number"}}],"responses":{"200":{"description":"Geometria do trajeto","content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"array","items":{"type":"object","properties":{"latitude":{"type":"number"},"longitude":{"type":"number"}}}},"distanceKm":{"type":"number"},"durationMinutes":{"type":"number"},"encodedPolyline":{"type":"string"}}}}}},"401":{"description":"Não autenticado"}}}},"/api/places/{placeId}":{"get":{"operationId":"placesGetDetails","summary":"Detalhes de um lugar","tags":["Places"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"placeId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detalhes do lugar"},"401":{"description":"Não autenticado"}}}},"/health":{"get":{"summary":"Verificar status da API","tags":["Health"],"responses":{"200":{"description":"API está funcionando","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"timestamp":{"type":"string","format":"date-time"}}}}}}}}},"/api/public/deliveries/{trackingCode}/status":{"get":{"operationId":"publicGetDeliveryStatus","summary":"Consultar status público da entrega","description":"Rastreamento público por trackingCode, sem autenticação. Não expõe motorista, placa, GPS nem dados financeiros. estimatedDelivery atualmente sempre retorna null. Timeline vem de trackingHistory (createdAt asc), sem latitude/longitude.","tags":["Public"],"parameters":[{"name":"trackingCode","in":"path","required":true,"schema":{"type":"string"},"description":"Código de rastreio da entrega"}],"responses":{"200":{"description":"Status público da entrega","content":{"application/json":{"schema":{"type":"object","required":["trackingCode","status","statusLabel","pickupAddress","deliveryAddress","estimatedDelivery","timeline"],"properties":{"trackingCode":{"type":"string"},"status":{"type":"string","enum":["PENDING","ACCEPTED","WAITING_AT_PICKUP","IN_TRANSIT","DELIVERED","CANCELLED"]},"statusLabel":{"type":"string","description":"PENDING: Aguardando motorista; ACCEPTED: Motorista a caminho; WAITING_AT_PICKUP: Motorista no ponto de coleta; IN_TRANSIT: Em trânsito; DELIVERED: Entregue; CANCELLED: Cancelada"},"pickupAddress":{"type":"string"},"deliveryAddress":{"type":"string"},"estimatedDelivery":{"type":"null","description":"Sempre null nesta versão"},"timeline":{"type":"array","items":{"type":"object","required":["status","description","notes","occurredAt"],"properties":{"status":{"type":"string","enum":["PENDING","ACCEPTED","WAITING_AT_PICKUP","IN_TRANSIT","DELIVERED","CANCELLED"]},"description":{"type":"string"},"notes":{"type":["string","null"]},"occurredAt":{"type":"string","format":"date-time"}}}}}}}}},"404":{"description":"Entrega não encontrada para o trackingCode informado"},"500":{"description":"Erro interno do servidor"}}}},"/api/auth/firebase/exchange":{"post":{"operationId":"authFirebaseExchange","summary":"Trocar Firebase ID Token por tokens internos","description":"Verifica o token do Firebase e retorna tokens JWT internos. Contas com senha precisam ter email verificado. Se o usuário não existir, cria automaticamente com os dados do Firebase. Se o email pertence a outro UID Firebase, exige vínculo explícito.","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["idToken"],"properties":{"idToken":{"type":"string","description":"Firebase ID Token obtido no cliente"},"roles":{"type":"array","items":{"type":"string","enum":["DRIVER","SENDER","RECIPIENT"]},"description":"Roles iniciais (apenas para novo usuário)"},"displayName":{"type":"string"},"phone":{"type":"string"}}},"examples":{"newSender":{"summary":"Novo remetente","value":{"idToken":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...","roles":["SENDER"]}},"newDriver":{"summary":"Novo motorista","value":{"idToken":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...","roles":["DRIVER"],"displayName":"João Silva","phone":"+5511999999999"}}}}}},"responses":{"200":{"description":"Tokens gerados com sucesso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"401":{"description":"Token do Firebase inválido ou expirado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Usuário inativo ou email da conta com senha não verificado (EMAIL_NOT_VERIFIED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Email já pertence a outra identidade Firebase (ACCOUNT_LINK_REQUIRED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/refresh":{"post":{"operationId":"authRefresh","summary":"Renovar access token","description":"Usa o refresh token para obter um novo access token. activeRole opcional preserva o papel selecionado se ainda estiver autorizado.","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["refreshToken"],"properties":{"refreshToken":{"type":"string","description":"Refresh token obtido no login"},"activeRole":{"type":"string","enum":["ADMIN","SENDER","RECIPIENT","DRIVER"],"description":"Papel ativo desejado, validado contra os papéis autorizados do usuário"}}}}}},"responses":{"200":{"description":"Novo access token","content":{"application/json":{"schema":{"type":"object","properties":{"accessToken":{"type":"string"},"expiresIn":{"type":"integer","example":900}}}}}},"401":{"description":"Refresh token inválido, expirado ou revogado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/logout":{"post":{"operationId":"authLogout","summary":"Fazer logout","description":"Revoga o refresh token atual, invalidando a sessão.","tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string"}}}}}},"responses":{"200":{"description":"Logout realizado","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Logout realizado com sucesso"}}}}}}}}},"/api/auth/logout-all":{"post":{"operationId":"authLogoutAll","summary":"Logout de todos os dispositivos","description":"Revoga todos os refresh tokens do usuário, desconectando de todos os dispositivos.","tags":["Auth"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Logout realizado em todos os dispositivos","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Logout realizado em todos os dispositivos"}}}}}},"401":{"description":"Não autenticado"}}}},"/api/auth/role-switch":{"post":{"operationId":"authRoleSwitch","summary":"Trocar a role ativa do usuário","description":"Emite um novo accessToken com a claim `activeRole` atualizada. Não rotaciona o refresh token. Use quando um usuário multi-papel (ex.: SENDER+DRIVER) quiser alternar contextos.","tags":["Auth"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["activeRole"],"properties":{"activeRole":{"type":"string","enum":["SENDER","RECIPIENT","DRIVER","ADMIN"]}}}}}},"responses":{"200":{"description":"Role ativa trocada com sucesso","content":{"application/json":{"schema":{"type":"object","required":["accessToken","tokenType","expiresIn","activeRole","roles"],"properties":{"accessToken":{"type":"string"},"tokenType":{"type":"string","example":"Bearer"},"expiresIn":{"type":"integer","example":900},"activeRole":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Payload inválido"},"401":{"description":"Não autenticado"},"403":{"description":"Role solicitada não está disponível para o usuário"}}}},"/api/auth/me":{"get":{"operationId":"authGetMe","summary":"Obter perfil do usuário atual","description":"Quando o usuário tem driverProfile, a resposta inclui averageRating (null se não houver avaliações), ratingsCount e completedDeliveries (entregas DELIVERED). A resposta também reflete a activeRole da sessão atual e expõe mobileRoles para clientes que alternam contexto entre sender, recipient e driver.","tags":["Auth","Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Perfil do usuário","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfile"}}}},"401":{"description":"Não autenticado"},"404":{"description":"Usuário não encontrado"}}}},"/api/auth/register":{"post":{"operationId":"authRegister","summary":"Registrar novo usuário","description":"Cria um novo usuário no sistema. Normalmente feito automaticamente pelo exchange.","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["firebaseUid","roles"],"properties":{"firebaseUid":{"type":"string"},"email":{"type":"string","format":"email"},"displayName":{"type":"string"},"phone":{"type":"string"},"roles":{"type":"array","items":{"type":"string","enum":["DRIVER","SENDER","RECIPIENT"]}}}}}}},"responses":{"201":{"description":"Usuário criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"409":{"description":"Usuário já existe"}}}},"/api/auth/add-driver-profile":{"post":{"operationId":"authAddDriverProfile","summary":"Adicionar perfil de motorista","description":"Adiciona os dados de veículo (marca, modelo, ano, cor, placa) e capacidade (litros + kg) para solicitar o papel de motorista. A capacidade informada alimenta a regra de declare trip.","tags":["Auth","Users"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["vehicleType","vehiclePlate","vehicleBrand","vehicleModel","vehicleYear","vehicleColor","trunkLiters","maxWeightKg"],"properties":{"legalName":{"type":"string","example":"Maria da Silva","description":"Nome legal completo. Opcional durante a transição de versões."},"cpf":{"type":"string","example":"52998224725","description":"CPF válido. Aceita pontuação e persiste somente dígitos."},"phone":{"type":"string","example":"(44) 99999-9999","description":"Telefone brasileiro normalizado para E.164."},"vehicleType":{"$ref":"#/components/schemas/VehicleType"},"vehiclePlate":{"type":"string","example":"ABC1D23"},"vehicleBrand":{"type":"string","example":"Fiat"},"vehicleModel":{"type":"string","example":"Argo"},"vehicleYear":{"type":"integer","example":2022},"vehicleColor":{"type":"string","example":"Prata"},"trunkLiters":{"type":"number","example":300,"description":"Capacidade do bagageiro/baú em litros"},"maxWeightKg":{"type":"number","example":400,"description":"Peso máximo suportado em kg"},"driverLicense":{"type":"string","example":"02650306461"},"licenseExpiry":{"type":"string","format":"date-time"}}}}}},"responses":{"201":{"description":"Perfil de motorista criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriverProfile"}}}},"400":{"description":"Campos de veículo/capacidade inválidos ou ausentes"},"401":{"description":"Não autenticado"},"409":{"description":"Perfil já existe"}}}},"/api/auth/add-address":{"post":{"operationId":"authAddAddress","summary":"Adicionar endereço","description":"Adiciona um endereço aos favoritos do usuário.","tags":["Auth","Users"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["street","number","neighborhood","city","state","zipCode"],"properties":{"label":{"type":"string","example":"Casa"},"street":{"type":"string","example":"Rua das Flores"},"number":{"type":"string","example":"123"},"complement":{"type":"string","example":"Apto 101"},"neighborhood":{"type":"string","example":"Centro"},"city":{"type":"string","example":"São Paulo"},"state":{"type":"string","example":"SP"},"zipCode":{"type":"string","example":"01310-100"},"isDefault":{"type":"boolean","default":false}}}}}},"responses":{"201":{"description":"Endereço criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Address"}}}},"401":{"description":"Não autenticado"}}}},"/api/auth/update-roles":{"put":{"operationId":"authUpdateRoles","summary":"Atualizar perfis do usuário","description":"Atualiza os perfis/roles do usuário atual.","tags":["Auth","Users"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["roles"],"properties":{"roles":{"type":"array","items":{"type":"string","enum":["DRIVER","SENDER","RECIPIENT"]}}}}}}},"responses":{"200":{"description":"Perfis atualizados","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Não autenticado"}}}},"/api/auth/push-tokens":{"post":{"operationId":"authRegisterPushToken","summary":"Registrar push token do dispositivo","description":"Faz upsert do token FCM/APNs do dispositivo autenticado. Tokens inválidos são desativados pelo worker de push.","tags":["Auth","Notifications"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterPushTokenRequest"}}}},"responses":{"201":{"description":"Push token registrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushToken"}}}},"400":{"description":"Payload inválido"},"401":{"description":"Não autenticado"}}},"delete":{"operationId":"authDeactivatePushToken","summary":"Desativar push token do dispositivo","description":"Marca o token informado como inativo (logout do dispositivo / opt-out).","tags":["Auth","Notifications"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeactivatePushTokenRequest"}}}},"responses":{"204":{"description":"Push token desativado"},"400":{"description":"Payload inválido"},"401":{"description":"Não autenticado"}}}},"/api/auth/notifications":{"get":{"operationId":"authListNotifications","summary":"Listar notificações do usuário","description":"Retorna a inbox paginada de notificações do usuário autenticado.","tags":["Auth","Notifications"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"unreadOnly","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}}],"responses":{"200":{"description":"Lista de notificações","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationListResponse"}}}},"400":{"description":"Query inválida"},"401":{"description":"Não autenticado"}}}},"/api/auth/notifications/read-all":{"post":{"operationId":"authMarkAllNotificationsAsRead","summary":"Marcar todas as notificações como lidas","tags":["Auth","Notifications"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Notificações marcadas como lidas","content":{"application/json":{"schema":{"type":"object","required":["markedAsRead"],"properties":{"markedAsRead":{"type":"integer","minimum":0}}}}}},"401":{"description":"Não autenticado"}}}},"/api/auth/notifications/{notificationId}/read":{"post":{"operationId":"authMarkNotificationAsRead","summary":"Marcar uma notificação como lida","tags":["Auth","Notifications"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"notificationId","in":"path","required":true,"schema":{"type":"string","maxLength":191}}],"responses":{"200":{"description":"Notificação marcada como lida","content":{"application/json":{"schema":{"type":"object","required":["id","readAt"],"properties":{"id":{"type":"string"},"readAt":{"type":"string","format":"date-time","nullable":true}}}}}},"400":{"description":"Parâmetros inválidos"},"401":{"description":"Não autenticado"},"404":{"description":"Notificação não encontrada"}}}},"/api/freight/calculate":{"post":{"summary":"Calcular frete","description":"Calcula o valor estimado do frete com base na origem, destino, peso e dimensões. Usa a API do Google Maps para calcular distância e tempo estimado.","tags":["Freight"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FreightCalculationRequest"},"examples":{"motorcycle":{"summary":"Entrega de moto","value":{"pickupAddress":"Av. Paulista, 1000, São Paulo, SP","deliveryAddress":"Rua Augusta, 500, São Paulo, SP","weight":2.5,"vehicleType":"MOTORCYCLE"}},"car":{"summary":"Entrega de carro","value":{"pickupAddress":"Av. Paulista, 1000, São Paulo, SP","deliveryAddress":"Rua Augusta, 500, São Paulo, SP","weight":15,"length":50,"width":40,"height":30,"declaredValue":500,"vehicleType":"CAR"}}}}}},"responses":{"200":{"description":"Frete calculado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FreightCalculationResponse"}}}},"400":{"description":"Dados inválidos"},"503":{"description":"Erro ao calcular rota (Google Maps)"}}}},"/api/sender/items":{"get":{"summary":"Listar meus itens cadastrados","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/ItemStatus"},"description":"Filtrar por status"},{"name":"productType","in":"query","schema":{"$ref":"#/components/schemas/ProductType"},"description":"Filtrar por tipo de produto"},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Lista de itens paginada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemListResponse"}}}},"401":{"description":"Não autenticado"},"403":{"description":"Sem permissão (não é SENDER)"}}},"post":{"summary":"Criar item completo","description":"Cria um item com todos os dados de uma vez.","tags":["Items"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","productType","declaredValue","weight"],"properties":{"name":{"type":"string","maxLength":200},"productType":{"$ref":"#/components/schemas/ProductType"},"description":{"type":"string"},"declaredValue":{"type":"number","minimum":0},"height":{"type":"number","description":"cm"},"width":{"type":"number","description":"cm"},"length":{"type":"number","description":"cm"},"weight":{"type":"number","minimum":0.001,"description":"kg"},"labels":{"type":"array","items":{"$ref":"#/components/schemas/ItemLabel"}}}},"examples":{"electronics":{"summary":"Eletrônico","value":{"name":"iPhone 15 Pro","productType":"ELECTRONICS","description":"Celular novo na caixa","declaredValue":8000,"weight":0.5,"labels":["FRAGILE","HIGH_VALUE"]}},"furniture":{"summary":"Móvel","value":{"name":"Mesa de escritório","productType":"FURNITURE","description":"Mesa desmontada","declaredValue":1500,"height":80,"width":120,"length":60,"weight":25,"labels":["HANDLE_WITH_CARE"]}}}}}},"responses":{"201":{"description":"Item criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Item"}}}},"400":{"description":"Dados inválidos"},"401":{"description":"Não autenticado"}}}},"/api/sender/items/draft":{"post":{"summary":"Criar rascunho de item (Etapa 1)","description":"Inicia o cadastro do item com dados básicos. O item fica em status DRAFT.","tags":["Items"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","productType","declaredValue"],"properties":{"name":{"type":"string"},"productType":{"$ref":"#/components/schemas/ProductType"},"description":{"type":"string"},"declaredValue":{"type":"number"}}}}}},"responses":{"201":{"description":"Rascunho criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Item"}}}},"400":{"description":"Dados inválidos"},"401":{"description":"Não autenticado"}}}},"/api/sender/items/product-types":{"get":{"summary":"Listar tipos de produto disponíveis","tags":["Items"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Lista de tipos de produto","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"}}}}}}}}}},"/api/sender/items/labels":{"get":{"summary":"Listar etiquetas/restrições disponíveis","tags":["Items"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Lista de etiquetas","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"prohibited":{"type":"boolean","description":"Se true, a etiqueta bloqueia cadastro/envio"},"requiresProfessionalDriver":{"type":"boolean"},"highValueThreshold":{"type":"number","description":"Presente em HIGH_VALUE; limiar configurável via ITEM_HIGH_VALUE_THRESHOLD"}}}}}}}}}},"/api/sender/items/weight-ranges":{"get":{"summary":"Listar faixas de peso disponíveis","tags":["Items"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Lista de faixas de peso com sugestão de veículo","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"minWeight":{"type":"number"},"maxWeight":{"type":"number"},"suggestedVehicle":{"$ref":"#/components/schemas/VehicleType"}}}}}}}}}},"/api/sender/items/{itemId}":{"get":{"summary":"Obter item por ID","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detalhes do item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Item"}}}},"401":{"description":"Não autenticado"},"404":{"description":"Item não encontrado"}}},"put":{"summary":"Atualizar item","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"productType":{"$ref":"#/components/schemas/ProductType"},"description":{"type":"string"},"declaredValue":{"type":"number"},"height":{"type":"number"},"width":{"type":"number"},"length":{"type":"number"},"weight":{"type":"number"},"labels":{"type":"array","items":{"$ref":"#/components/schemas/ItemLabel"}}}}}}},"responses":{"200":{"description":"Item atualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Item"}}}},"400":{"description":"Dados inválidos"},"401":{"description":"Não autenticado"},"404":{"description":"Item não encontrado"}}},"delete":{"summary":"Excluir item","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Item excluído"},"401":{"description":"Não autenticado"},"404":{"description":"Item não encontrado"}}}},"/api/sender/items/{itemId}/dimensions":{"put":{"summary":"Atualizar dimensões do item (Etapa 2)","description":"Adiciona peso, dimensões e etiquetas ao item em rascunho.","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["weight"],"properties":{"height":{"type":"number"},"width":{"type":"number"},"length":{"type":"number"},"weight":{"type":"number"},"labels":{"type":"array","items":{"$ref":"#/components/schemas/ItemLabel"}}}}}}},"responses":{"200":{"description":"Dimensões atualizadas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Item"}}}},"400":{"description":"Dados inválidos"},"401":{"description":"Não autenticado"},"404":{"description":"Item não encontrado"}}}},"/api/sender/items/{itemId}/finalize":{"put":{"summary":"Finalizar cadastro do item","description":"Muda o status do item de DRAFT para PENDING, tornando-o disponível para entregas.\n\nRequisitos: name, productType, declaredValue, height, width, length, weight (> 0) e ≥1 foto.\nDocumentos ainda opcionais. 400 lista missingFields quando incompleto.","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Item finalizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Item"}}}},"400":{"description":"Item incompleto — message + missingFields (dimensões, peso, fotos, etc.)"},"401":{"description":"Não autenticado"},"404":{"description":"Item não encontrado"},"409":{"description":"Item não está em DRAFT/PENDING"},"422":{"description":"Restrição de transporte proibida"}}}},"/api/sender/items/{itemId}/photos":{"post":{"summary":"Adicionar foto ao item","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","filename","mimeType","size"],"properties":{"url":{"type":"string","format":"uri"},"filename":{"type":"string"},"mimeType":{"type":"string"},"size":{"type":"integer"},"order":{"type":"integer","default":0}}}}}},"responses":{"201":{"description":"Foto adicionada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemPhoto"}}}},"401":{"description":"Não autenticado"},"404":{"description":"Item não encontrado"}}}},"/api/sender/items/{itemId}/photos/{photoId}":{"delete":{"summary":"Remover foto do item","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"photoId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Foto removida"},"401":{"description":"Não autenticado"},"404":{"description":"Item ou foto não encontrado"}}}},"/api/sender/items/{itemId}/documents":{"post":{"summary":"Adicionar documento ao item","description":"Adiciona nota fiscal, recibo ou outro documento ao item.","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","url","filename","mimeType","size"],"properties":{"type":{"type":"string","enum":["invoice","receipt","other"]},"url":{"type":"string","format":"uri"},"filename":{"type":"string"},"mimeType":{"type":"string"},"size":{"type":"integer"}}}}}},"responses":{"201":{"description":"Documento adicionado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDocument"}}}},"401":{"description":"Não autenticado"},"404":{"description":"Item não encontrado"}}}},"/api/sender/items/{itemId}/documents/{documentId}":{"delete":{"summary":"Remover documento do item","tags":["Items"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Documento removido"},"401":{"description":"Não autenticado"},"404":{"description":"Item ou documento não encontrado"}}}},"/api/sender/items/{itemId}/upload/photo":{"post":{"summary":"Upload de foto do item","description":"Faz upload direto de uma foto. Max 5MB, formatos: JPEG, PNG, WebP.","tags":["Items","Upload"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["photo"],"properties":{"photo":{"type":"string","format":"binary"},"caption":{"type":"string"}}}}}},"responses":{"201":{"description":"Foto uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemPhoto"}}}},"400":{"description":"Arquivo inválido"},"413":{"description":"Arquivo muito grande"}}}},"/api/sender/items/{itemId}/upload/photos":{"post":{"summary":"Upload múltiplo de fotos","description":"Faz upload de múltiplas fotos de uma vez. Max 10 fotos, 5MB cada.","tags":["Items","Upload"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["photos"],"properties":{"photos":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"201":{"description":"Fotos uploaded","content":{"application/json":{"schema":{"type":"object","properties":{"photos":{"type":"array","items":{"$ref":"#/components/schemas/ItemPhoto"}}}}}}},"400":{"description":"Arquivos inválidos"},"413":{"description":"Arquivos muito grandes"}}}},"/api/sender/items/{itemId}/upload/document":{"post":{"summary":"Upload de documento","description":"Faz upload de nota fiscal ou recibo. Max 10MB, formatos: PDF, JPEG, PNG.","tags":["Items","Upload"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["document","type"],"properties":{"document":{"type":"string","format":"binary"},"type":{"type":"string","enum":["invoice","receipt","other"]}}}}}},"responses":{"201":{"description":"Documento uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDocument"}}}},"400":{"description":"Arquivo inválido"},"413":{"description":"Arquivo muito grande"}}}},"/api/sender/items/{itemId}/upload/signed-url":{"post":{"summary":"Gerar URL assinada para upload direto","description":"Gera uma URL para o cliente fazer upload direto ao Firebase Storage.","tags":["Items","Upload"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["filename","contentType","fileType"],"properties":{"filename":{"type":"string"},"contentType":{"type":"string","example":"image/jpeg"},"fileType":{"type":"string","enum":["photo","document"]}}}}}},"responses":{"200":{"description":"URL assinada gerada","content":{"application/json":{"schema":{"type":"object","properties":{"uploadUrl":{"type":"string","format":"uri"},"publicUrl":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Parâmetros inválidos"}}}},"/api/sender/deliveries":{"get":{"summary":"Listar minhas entregas enviadas","tags":["Deliveries"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Um status ou CSV (`DELIVERED,CANCELLED`). Tem prioridade sobre `scope`.","schema":{"type":"string","example":"IN_TRANSIT"}},{"name":"scope","in":"query","required":false,"description":"Atalho semântico. `active` / `history` / `all`. Motorista: active = ACCEPTED|WAITING_AT_PICKUP|IN_TRANSIT. Cliente: active inclui PENDING.","schema":{"type":"string","enum":["active","history","all"]}},{"name":"from","in":"query","required":false,"description":"Filtro inclusive por createdAt (ISO date-time).","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Filtro inclusive por createdAt (ISO date-time).","schema":{"type":"string","format":"date-time"}},{"name":"page","in":"query","required":false,"description":"Quando presente, a resposta usa envelope paginado. Sem `page`, retorna array legado (compat).","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Itens por página (só com `page`). Default 20, máx 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Array legado (sem page) ou DeliveryListResponse (com page)","content":{"application/json":{"schema":{"oneOf":[{"type":"array","items":{"$ref":"#/components/schemas/Delivery"}},{"$ref":"#/components/schemas/DeliveryListResponse"}]}}}},"400":{"description":"Query inválida"},"401":{"description":"Não autenticado"}}},"post":{"summary":"Criar nova entrega","tags":["Deliveries"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["recipientId","pickupAddress","deliveryAddress","itemDescription","itemWeight"],"properties":{"recipientId":{"type":"string","format":"uuid"},"pickupAddress":{"type":"string"},"pickupContactName":{"type":"string"},"pickupContactPhone":{"type":"string"},"deliveryAddress":{"type":"string"},"deliveryContactName":{"type":"string"},"deliveryContactPhone":{"type":"string"},"itemDescription":{"type":"string"},"itemWeight":{"type":"number"},"itemValue":{"type":"number"},"itemLength":{"type":"number"},"itemWidth":{"type":"number"},"itemHeight":{"type":"number"},"itemLabels":{"type":"array","items":{"$ref":"#/components/schemas/ItemLabel"},"description":"Etiquetas quando a entrega não usa itemId. HAZARDOUS/FLAMMABLE retornam 422."},"itemId":{"type":"string","format":"uuid"},"scheduledPickupTime":{"type":"string","format":"date-time"},"notes":{"type":"string"}}}}}},"responses":{"201":{"description":"Entrega criada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"}}}},"400":{"description":"Dados inválidos"},"401":{"description":"Não autenticado"},"422":{"description":"Item com etiqueta proibida (PROHIBITED_ITEM)"}}}},"/api/sender/deliveries/{deliveryId}":{"delete":{"summary":"Cancelar entrega","tags":["Deliveries"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Entrega cancelada"},"401":{"description":"Não autenticado"},"404":{"description":"Entrega não encontrada"}}}},"/api/sender/deliveries/{deliveryId}/ratings":{"post":{"operationId":"senderCreateDeliveryRating","summary":"Avaliar o motorista da entrega","description":"Avaliação opcional de 1 a 5 estrelas após a entrega ser concluída (DELIVERED).","tags":["Deliveries"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRatingRequest"}}}},"responses":{"201":{"description":"Avaliação registrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRatingResponse"}}}},"400":{"description":"Rating inválido ou entrega ainda não concluída"},"401":{"description":"Não autenticado"},"403":{"description":"Não é o remetente da entrega, ou motorista tentando avaliar a si próprio"},"404":{"description":"Entrega não encontrada"},"409":{"description":"Avaliação duplicada para esta entrega e usuário"}}}},"/api/sender/deliveries/{deliveryId}/address-changes":{"get":{"operationId":"senderListAddressChanges","summary":"Listar solicitações de mudança de endereço da entrega","tags":["Deliveries"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED","CANCELLED"]}}],"responses":{"200":{"description":"Solicitações encontradas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryAddressChangeListResponse"}}}},"400":{"description":"Filtro inválido"},"401":{"description":"Não autenticado"},"404":{"description":"Entrega não encontrada"}}}},"/api/sender/deliveries/{deliveryId}/reschedule-requests":{"get":{"operationId":"senderListRescheduleRequests","summary":"Listar solicitações de reagendamento da entrega","tags":["Deliveries"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED","CANCELLED"]}}],"responses":{"200":{"description":"Solicitações encontradas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryRescheduleRequestListResponse"}}}},"400":{"description":"Filtro inválido"},"401":{"description":"Não autenticado"},"404":{"description":"Entrega não encontrada"}}}},"/api/recipient/deliveries":{"get":{"summary":"Listar entregas que vou receber","tags":["Deliveries"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Um status ou CSV (`DELIVERED,CANCELLED`). Tem prioridade sobre `scope`.","schema":{"type":"string","example":"IN_TRANSIT"}},{"name":"scope","in":"query","required":false,"description":"Atalho semântico. `active` / `history` / `all`. Motorista: active = ACCEPTED|WAITING_AT_PICKUP|IN_TRANSIT. Cliente: active inclui PENDING.","schema":{"type":"string","enum":["active","history","all"]}},{"name":"from","in":"query","required":false,"description":"Filtro inclusive por createdAt (ISO date-time).","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Filtro inclusive por createdAt (ISO date-time).","schema":{"type":"string","format":"date-time"}},{"name":"page","in":"query","required":false,"description":"Quando presente, a resposta usa envelope paginado. Sem `page`, retorna array legado (compat).","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Itens por página (só com `page`). Default 20, máx 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Array legado (sem page) ou DeliveryListResponse (com page)","content":{"application/json":{"schema":{"oneOf":[{"type":"array","items":{"$ref":"#/components/schemas/Delivery"}},{"$ref":"#/components/schemas/DeliveryListResponse"}]}}}},"400":{"description":"Query inválida"},"401":{"description":"Não autenticado"}}}},"/api/recipient/deliveries/{deliveryId}/ratings":{"post":{"operationId":"recipientCreateDeliveryRating","summary":"Avaliar o motorista da entrega","description":"Avaliação opcional de 1 a 5 estrelas após a entrega ser concluída (DELIVERED).","tags":["Deliveries"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRatingRequest"}}}},"responses":{"201":{"description":"Avaliação registrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRatingResponse"}}}},"400":{"description":"Rating inválido ou entrega ainda não concluída"},"401":{"description":"Não autenticado"},"403":{"description":"Não é o destinatário da entrega, ou motorista tentando avaliar a si próprio"},"404":{"description":"Entrega não encontrada"},"409":{"description":"Avaliação duplicada para esta entrega e usuário"}}}},"/api/driver/deliveries/available":{"get":{"operationId":"driverListAvailableDeliveries","summary":"Listar entregas disponíveis","description":"Lista ofertas PENDING cuja coleta está a até `radiusKm` (padrão 100) da localização atual do motorista. Não exige Trip ACTIVE.","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"radiusKm","in":"query","required":false,"schema":{"type":"number","exclusiveMinimum":0,"maximum":200,"default":100}}],"responses":{"200":{"description":"Lista de ofertas próximas","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteOffer"}}}}},"400":{"description":"Query inválida ou localização ausente"},"401":{"description":"Não autenticado"},"403":{"description":"Não é motorista"}}}},"/api/driver/deliveries/compatible":{"get":{"summary":"Entregas compatíveis com o trajeto","description":"Matching por corredor de rota (WELOZ-25). Lista encomendas cuja origem e destino estão ao longo do trajeto declarado.","operationId":"listCompatibleDeliveries","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"routeId","in":"query","required":true,"schema":{"type":"string"},"description":"Identificador do trajeto declarado (Card 12)."}],"responses":{"200":{"description":"Lista de ofertas compatíveis com o corredor","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteOffer"}}}}},"400":{"description":"routeId ausente ou inválido"},"401":{"description":"Não autenticado"},"403":{"description":"Não é motorista"},"404":{"description":"Trajeto não encontrado"}}}},"/api/driver/deliveries":{"get":{"summary":"Listar minhas entregas como motorista","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Um status ou CSV (`DELIVERED,CANCELLED`). Tem prioridade sobre `scope`.","schema":{"type":"string","example":"IN_TRANSIT"}},{"name":"scope","in":"query","required":false,"description":"Atalho semântico. `active` / `history` / `all`. Motorista: active = ACCEPTED|WAITING_AT_PICKUP|IN_TRANSIT. Cliente: active inclui PENDING.","schema":{"type":"string","enum":["active","history","all"]}},{"name":"from","in":"query","required":false,"description":"Filtro inclusive por createdAt (ISO date-time).","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Filtro inclusive por createdAt (ISO date-time).","schema":{"type":"string","format":"date-time"}},{"name":"page","in":"query","required":false,"description":"Quando presente, a resposta usa envelope paginado. Sem `page`, retorna array legado (compat).","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Itens por página (só com `page`). Default 20, máx 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Array legado (sem page) ou DeliveryListResponse (com page)","content":{"application/json":{"schema":{"oneOf":[{"type":"array","items":{"$ref":"#/components/schemas/Delivery"}},{"$ref":"#/components/schemas/DeliveryListResponse"}]}}}},"400":{"description":"Query inválida"},"401":{"description":"Não autenticado"},"403":{"description":"Não é motorista"}}}},"/api/driver/deliveries/{deliveryId}/accept":{"post":{"summary":"Aceitar entrega","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Entrega aceita","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"}}}},"400":{"description":"Entrega não está disponível"},"401":{"description":"Não autenticado"},"403":{"description":"Não é motorista"},"404":{"description":"Entrega não encontrada"},"409":{"description":"Sem trajeto ativo, capacidade do veículo/tier esgotada, pagamento sem autorização/reserva vencida, ou entrega aceita por outro motorista","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","enum":["ACTIVE_TRIP_REQUIRED","CAPACITY_EXCEEDED","TIER_ITEM_LIMIT_EXCEEDED","DELIVERY_ALREADY_ACCEPTED","DELIVERY_PAYMENT_NOT_AUTHORIZED","DELIVERY_PAYMENT_AUTHORIZATION_EXPIRED"]},"message":{"type":"string"}}},"examples":{"capacityExceeded":{"summary":"Capacidade da trip excedida após revalidação transacional","value":{"error":"CAPACITY_EXCEEDED","message":"Esta entrega (10kg) ultrapassa a capacidade restante do veículo (5kg de 100kg)."}}}}}}}}},"/api/driver/deliveries/{deliveryId}/status":{"patch":{"summary":"Atualizar status da entrega","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"$ref":"#/components/schemas/DeliveryStatus"},"notes":{"type":"string"}}}}}},"responses":{"200":{"description":"Status atualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"}}}},"400":{"description":"Transição de status inválida"},"401":{"description":"Não autenticado"},"403":{"description":"Não é o motorista desta entrega"},"404":{"description":"Entrega não encontrada"}}}},"/api/driver/deliveries/{deliveryId}/transfer":{"post":{"operationId":"transferDeliveryByDriver","summary":"Solicitar repasse da entrega","description":"O motorista atual informa que não consegue concluir a entrega e registra o motivo do repasse. `deliveryId` vai no path; o motorista autenticado é o solicitante.","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferDeliveryRequest"}}}},"responses":{"200":{"description":"Solicitação de repasse aceita","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"}}}},"400":{"description":"Payload inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Não autenticado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Não é o motorista desta entrega","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entrega não encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/driver/deliveries/{deliveryId}/handoff":{"post":{"operationId":"assumeTransferredDelivery","summary":"Assumir entrega após repasse","description":"O novo motorista assume uma entrega liberada para repasse. O pacote já foi coletado, então o status volta para IN_TRANSIT e a cadeia de custódia registra o sucessor.","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Entrega assumida em trânsito","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"}}}},"400":{"description":"Payload inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Não autenticado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Motorista não habilitado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entrega ou perfil de motorista não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Handoff inválido (mesmo motorista, já assumida ou pacote não coletado)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/driver/deliveries/{deliveryId}/custody":{"get":{"operationId":"getDeliveryCustodyHistory","summary":"Consultar cadeia de custódia","description":"Lista os períodos de custódia da entrega em ordem cronológica.","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Cadeia de custódia","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DeliveryCustodyRecord"}}}}},"401":{"description":"Não autenticado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sem permissão para consultar a cadeia","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entrega não encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/driver/location":{"patch":{"summary":"Atualizar localização do motorista","tags":["Driver"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["latitude","longitude"],"properties":{"latitude":{"type":"number"},"longitude":{"type":"number"}}}}}},"responses":{"200":{"description":"Localização atualizada"},"401":{"description":"Não autenticado"},"403":{"description":"Não é motorista"}}}},"/api/admin/users":{"get":{"summary":"Listar todos os usuários","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}},{"name":"role","in":"query","schema":{"$ref":"#/components/schemas/UserRole"}},{"name":"isActive","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Lista de usuários","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/User"}},"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"}}}}}},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"}}}},"/api/admin/users/{userId}/deactivate":{"patch":{"summary":"Desativar usuário","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Usuário desativado"},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"},"404":{"description":"Usuário não encontrado"}}}},"/api/admin/users/{userId}/activate":{"patch":{"summary":"Ativar usuário","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Usuário ativado"},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"},"404":{"description":"Usuário não encontrado"}}}},"/api/admin/deliveries":{"get":{"summary":"Listar todas as entregas","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/DeliveryStatus"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Lista de entregas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryListResponse"}}}},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"}}}},"/api/admin/deliveries/{deliveryId}":{"delete":{"summary":"Cancelar qualquer entrega","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Entrega cancelada"},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"},"404":{"description":"Entrega não encontrada"}}}},"/api/admin/cities":{"get":{"operationId":"adminListCities","summary":"Listar cidades atendidas","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"state","in":"query","schema":{"type":"string","minLength":2,"maxLength":2}},{"name":"isActive","in":"query","schema":{"type":"string","enum":["true","false"]}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Lista paginada de cidades","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CityListResponse"}}}}}},"post":{"operationId":"adminCreateCity","summary":"Criar cidade atendida","tags":["Admin"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCityRequest"}}}},"responses":{"201":{"description":"Cidade criada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/City"}}}},"409":{"description":"Cidade já existe para este estado"}}}},"/api/admin/cities/{cityId}":{"get":{"operationId":"adminGetCity","summary":"Obter cidade pelo id","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"cityId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/City"}}}},"404":{"description":"Cidade não encontrada"}}},"patch":{"operationId":"adminUpdateCity","summary":"Atualizar cidade","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"cityId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCityRequest"}}}},"responses":{"200":{"description":"Cidade atualizada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/City"}}}},"404":{"description":"Cidade não encontrada"},"409":{"description":"Conflito (nome duplicado no estado)"}}},"delete":{"operationId":"adminDeleteCity","summary":"Remover cidade","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"cityId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Cidade removida"},"404":{"description":"Cidade não encontrada"}}}},"/api/admin/cities/{cityId}/pricing":{"get":{"operationId":"adminGetCityPricing","summary":"Obter pricing da cidade","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"cityId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Pricing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CityPricing"}}}},"404":{"description":"Pricing não cadastrado"}}},"put":{"operationId":"adminUpsertCityPricing","summary":"Criar ou atualizar pricing da cidade","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"cityId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertCityPricingRequest"}}}},"responses":{"200":{"description":"Pricing salvo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CityPricing"}}}},"404":{"description":"Cidade não encontrada"}}},"delete":{"operationId":"adminDeleteCityPricing","summary":"Remover pricing da cidade","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"cityId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Pricing removido"},"404":{"description":"Pricing não cadastrado"}}}},"/api/driver/vehicle":{"patch":{"operationId":"driverUpdateVehicle","summary":"Atualizar veículo e capacidade","description":"Completa ou corrige dados do veículo e capacidade (litros + kg) no perfil de motorista existente. Disponível sem exigir aprovação DRIVER.","tags":["Driver","Profile"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["vehicleType","vehiclePlate","vehicleBrand","vehicleModel","vehicleYear","vehicleColor","trunkLiters","maxWeightKg"],"properties":{"legalName":{"type":"string","example":"Maria da Silva"},"cpf":{"type":"string","example":"52998224725"},"phone":{"type":"string","example":"(44) 99999-9999"},"vehicleType":{"$ref":"#/components/schemas/VehicleType"},"vehiclePlate":{"type":"string","example":"ABC1D23"},"vehicleBrand":{"type":"string","example":"Fiat"},"vehicleModel":{"type":"string","example":"Argo"},"vehicleYear":{"type":"integer","example":2022},"vehicleColor":{"type":"string","example":"Prata"},"trunkLiters":{"type":"number","example":300},"maxWeightKg":{"type":"number","example":400},"driverLicense":{"type":"string"},"licenseExpiry":{"type":"string","format":"date-time"}}}}}},"responses":{"200":{"description":"Perfil atualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriverProfile"}}}},"400":{"description":"Dados inválidos"},"401":{"description":"Não autenticado"},"403":{"description":"Negado permanentemente (fora da janela de reaplicação)"},"404":{"description":"Perfil de motorista não encontrado"}}}},"/api/driver/vehicles/catalog":{"get":{"operationId":"getDriverVehicleCatalog","summary":"Consultar catálogo encadeado de veículos","description":"Retorna marcas para o tipo informado, modelos após a marca, anos após o modelo e as cores veiculares aceitas.","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"vehicleType","in":"query","required":true,"schema":{"$ref":"#/components/schemas/VehicleType"}},{"name":"brand","in":"query","schema":{"type":"string"}},{"name":"model","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Opções disponíveis para a seleção atual","content":{"application/json":{"schema":{"type":"object","required":["brands","models","years","colors"],"properties":{"brands":{"type":"array","items":{"type":"string"}},"models":{"type":"array","items":{"type":"string"}},"years":{"type":"array","items":{"type":"integer"}},"colors":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Consulta inválida"},"401":{"description":"Não autenticado"}}}},"/api/driver/vehicles/capacity-suggestion":{"post":{"operationId":"suggestVehicleCapacity","summary":"Sugerir capacidade do veículo","description":"Consulta tabela de modelos (e opcionalmente placa) para sugerir litros/kg do porta-malas. Não converte litros em kg.","tags":["Driver"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuggestVehicleCapacityRequest"}}}},"responses":{"200":{"description":"Sugestão de capacidade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuggestVehicleCapacityResponse"}}}},"400":{"description":"Payload inválido"},"401":{"description":"Não autenticado"},"403":{"description":"Não é motorista"}}}},"/api/admin/vehicle-model-capacities":{"get":{"operationId":"listVehicleModelCapacities","summary":"Listar capacidades por modelo","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"brand","in":"query","schema":{"type":"string"}},{"name":"model","in":"query","schema":{"type":"string"}},{"name":"bodyCategory","in":"query","schema":{"$ref":"#/components/schemas/VehicleBodyCategory"}},{"name":"isActive","in":"query","schema":{"type":"string","enum":["true","false"]}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"Lista paginada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleModelCapacityListResponse"}}}},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"}}},"post":{"operationId":"createVehicleModelCapacity","summary":"Criar capacidade de modelo","tags":["Admin"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVehicleModelCapacityRequest"}}}},"responses":{"201":{"description":"Modelo criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleModelCapacity"}}}},"400":{"description":"Payload inválido"},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"}}}},"/api/admin/vehicle-model-capacities/{id}":{"get":{"operationId":"getVehicleModelCapacity","summary":"Obter capacidade de modelo","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Modelo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleModelCapacity"}}}},"404":{"description":"Modelo não encontrado"}}},"patch":{"operationId":"updateVehicleModelCapacity","summary":"Atualizar capacidade de modelo","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVehicleModelCapacityRequest"}}}},"responses":{"200":{"description":"Modelo atualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleModelCapacity"}}}},"400":{"description":"Payload inválido"},"404":{"description":"Modelo não encontrado"}}},"delete":{"operationId":"deleteVehicleModelCapacity","summary":"Remover capacidade de modelo","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Modelo removido"},"404":{"description":"Modelo não encontrado"}}}},"/api/admin/vehicle-category-capacities":{"get":{"operationId":"listVehicleCategoryCapacities","summary":"Listar capacidades por categoria","tags":["Admin"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Lista de categorias","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/VehicleCategoryCapacity"}}}}}}},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"}}}},"/api/admin/vehicle-category-capacities/{bodyCategory}":{"put":{"operationId":"upsertVehicleCategoryCapacity","summary":"Criar ou atualizar capacidade da categoria","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"bodyCategory","in":"path","required":true,"schema":{"$ref":"#/components/schemas/VehicleBodyCategory"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertVehicleCategoryCapacityRequest"}}}},"responses":{"200":{"description":"Categoria salva","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleCategoryCapacity"}}}},"400":{"description":"Payload inválido"},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"}}}},"/api/admin/payment-policy":{"get":{"operationId":"adminGetPaymentPolicy","tags":["Admin"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Política de pagamento"}}},"patch":{"operationId":"adminUpdatePaymentPolicy","tags":["Admin"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["platformFeeBps","processorFeePayer"],"properties":{"platformFeeBps":{"type":"integer","minimum":0,"maximum":10000},"processorFeePayer":{"type":"string","enum":["PLATFORM"]}}}}}},"responses":{"200":{"description":"Política atualizada"}}}},"/api/sender/payment/receivables":{"get":{"operationId":"senderListPaymentReceivables","tags":["Payments"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Pendências abertas"}}}},"/api/sender/payment/receivables/{receivableId}/checkout":{"post":{"operationId":"senderCheckoutPaymentReceivable","tags":["Payments"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"receivableId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Checkout da dívida"}}}},"/api/payments/webhooks/stripe":{"post":{"operationId":"stripePaymentWebhook","tags":["Payments"],"summary":"Webhook Stripe assinado","responses":{"200":{"description":"Evento processado"},"401":{"description":"Assinatura inválida"}}}},"/api/payments/webhooks/stripe/connect":{"post":{"operationId":"stripeConnectWebhook","tags":["Payments"],"summary":"Webhook assinado de eventos thin do Stripe Connect Accounts v2","responses":{"200":{"description":"Evento Connect processado"},"401":{"description":"Assinatura inválida"}}}},"/api/driver/payment-account/status":{"get":{"operationId":"driverGetPayoutAccountStatus","tags":["Driver","Payments"],"security":[{"bearerAuth":[]}],"summary":"Consultar elegibilidade da conta Stripe Connect do motorista","responses":{"200":{"description":"Estado atual da conta de recebimentos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriverPayoutAccountStatus"}}}},"401":{"description":"Não autenticado"},"403":{"description":"Motorista ainda não aprovado"}}}},"/api/driver/payment-account/onboarding":{"post":{"operationId":"driverStartPayoutAccountOnboarding","tags":["Driver","Payments"],"security":[{"bearerAuth":[]}],"summary":"Criar ou retomar o onboarding hospedado do Stripe Connect","responses":{"200":{"description":"URL temporária de uso único","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/DriverPayoutAccountStatus"},{"type":"object","required":["onboardingUrl"],"properties":{"onboardingUrl":{"type":"string","format":"uri"},"expiresAt":{"type":["string","null"],"format":"date-time"}}}]}}}},"409":{"description":"Conta em estado incompatível"},"422":{"description":"Email obrigatório"},"503":{"description":"Configuração Stripe indisponível"}}}},"/api/payments/checkout/stripe/result":{"get":{"operationId":"stripeCheckoutResult","tags":["Payments"],"summary":"Página de retorno do checkout Stripe","responses":{"200":{"description":"Voltar ao app"}}}},"/api/payments/connect/onboarding-return":{"get":{"operationId":"stripeConnectOnboardingReturn","tags":["Payments"],"summary":"Página de retorno do onboarding Stripe Connect","responses":{"200":{"description":"Orientação para voltar ao app"}}}},"/api/payments/connect/onboarding-refresh":{"get":{"operationId":"stripeConnectOnboardingRefresh","tags":["Payments"],"summary":"Página para link de onboarding expirado ou já utilizado","responses":{"200":{"description":"Orientação para gerar novo link no app"}}}},"/api/support/threads":{"get":{"operationId":"listSupportThreads","tags":["Support"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Conversas do usuário ou do suporte"}}},"post":{"operationId":"createSupportThread","tags":["Support"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"deliveryId":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Conversa criada ou reutilizada"}}}},"/api/support/threads/{threadId}/messages":{"get":{"operationId":"listSupportMessages","tags":["Support"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Mensagens da conversa"}}},"post":{"operationId":"sendSupportMessage","tags":["Support"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","minLength":1,"maxLength":2000}}}}}},"responses":{"201":{"description":"Mensagem enviada"}}}},"/api/support/threads/{threadId}/close":{"patch":{"operationId":"closeSupportThread","tags":["Support"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Conversa encerrada pelo suporte"}}}},"/api/driver/deliveries/{deliveryId}/proofs/return/photo":{"post":{"operationId":"driverUploadReturnProofPhoto","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"201":{"description":"Foto da devolução enviada"}}}},"/api/driver/deliveries/{deliveryId}/proofs/return":{"post":{"operationId":"driverRegisterReturnProof","tags":["Driver"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"201":{"description":"Prova da devolução registrada"}}}},"/api/sender/deliveries/{deliveryId}/return-confirm":{"post":{"operationId":"senderConfirmReturn","tags":["Sender"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Devolução confirmada pelo remetente"}}}},"/api/admin/drivers/{driverProfileId}/vehicle-capacity":{"patch":{"operationId":"adminOverrideDriverVehicleCapacity","summary":"Sobrescrever capacidade do veículo do motorista","tags":["Admin"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"driverProfileId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OverrideDriverVehicleCapacityRequest"}}}},"responses":{"200":{"description":"Capacidade atualizada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriverProfile"}}}},"400":{"description":"Payload inválido"},"401":{"description":"Não autenticado"},"403":{"description":"Não é admin"},"404":{"description":"Perfil de motorista não encontrado"}}}}}}