{"openapi":"3.0.0","paths":{"/api/v1/partner/quotes":{"post":{"operationId":"create-quote","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerQuoteDto"}}}},"default":{"description":"Erreur : `code` stable et message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorDto"}}}}},"security":[{"bearer":[]}],"summary":"Prix d’une course","tags":["API partenaires"]}},"/api/v1/partner/zones":{"get":{"operationId":"list-zones","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneMapDto"}}}},"default":{"description":"Erreur : `code` stable et message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorDto"}}}}},"security":[{"bearer":[]}],"summary":"Zones desservies","tags":["API partenaires"]}},"/api/v1/partner/pickup-addresses":{"get":{"operationId":"list-pickup-addresses","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PartnerAddressDto"}}}}},"default":{"description":"Erreur : `code` stable et message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorDto"}}}}},"security":[{"bearer":[]}],"summary":"Adresses d’enlèvement de la boutique","tags":["API partenaires"]}},"/api/v1/partner/deliveries":{"post":{"operationId":"create-delivery","parameters":[{"name":"Idempotency-Key","in":"header","description":"Identifiant unique de la demande","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerCreateDeliveryDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerCreatedDeliveryDto"}}}},"default":{"description":"Erreur : `code` stable et message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorDto"}}}}},"security":[{"bearer":[]}],"summary":"Créer une livraison","tags":["API partenaires"]},"get":{"operationId":"list-deliveries","parameters":[{"name":"status","required":false,"in":"query","description":"Statuts séparés par des virgules","schema":{"type":"array","items":{"$ref":"#/components/schemas/Object"}}},{"name":"from","required":false,"in":"query","schema":{"type":"string"}},{"name":"to","required":false,"in":"query","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"allOf":[{"$ref":"#/components/schemas/Object"}]}},{"name":"pageSize","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":30,"allOf":[{"$ref":"#/components/schemas/Object"}]}},{"name":"externalRef","required":false,"in":"query","schema":{"minLength":1,"maxLength":64,"example":"WC-10482","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerDeliveryPageDto"}}}},"default":{"description":"Erreur : `code` stable et message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorDto"}}}}},"security":[{"bearer":[]}],"summary":"Lister les livraisons","tags":["API partenaires"]}},"/api/v1/partner/deliveries/{id}":{"get":{"operationId":"get-delivery","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerDeliveryDto"}}}},"default":{"description":"Erreur : `code` stable et message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorDto"}}}}},"security":[{"bearer":[]}],"summary":"Détail d’une livraison","tags":["API partenaires"]}},"/api/v1/partner/deliveries/{id}/events":{"get":{"operationId":"list-delivery-events","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PartnerEventDto"}}}}},"default":{"description":"Erreur : `code` stable et message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorDto"}}}}},"security":[{"bearer":[]}],"summary":"Historique des statuts","tags":["API partenaires"]}},"/api/v1/partner/deliveries/{id}/cancel":{"post":{"operationId":"cancel-delivery","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerDeliveryDto"}}}},"default":{"description":"Erreur : `code` stable et message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorDto"}}}}},"security":[{"bearer":[]}],"summary":"Annuler une livraison","tags":["API partenaires"]}},"/api/v1/partner/sandbox/deliveries/{id}/advance":{"post":{"description":"Disponible uniquement sur la sandbox.","operationId":"advance-sandbox-delivery","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerDeliveryDto"}}}},"default":{"description":"Erreur : `code` stable et message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorDto"}}}}},"security":[{"bearer":[]}],"summary":"Sandbox : étape suivante","tags":["API partenaires"]}}},"info":{"title":"Fofo Express — API partenaires","description":"Créez et suivez vos livraisons Fofo Express depuis votre site ou votre logiciel. Authentification : `Authorization: Bearer <clé API>`.","version":"1","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"Clé API `fx_live_…`"}},"schemas":{"PartnerErrorDto":{"type":"object","properties":{"statusCode":{"type":"number","example":409},"code":{"type":"string","example":"EXTERNAL_REF_TAKEN","description":"Code stable, à utiliser dans votre code"},"message":{"type":"string","example":"Une livraison existe déjà pour cette référence de commande.","description":"Message en français ou en anglais selon `Accept-Language` ; un objet `details` peut préciser l’erreur"}},"required":["statusCode","code","message"]},"PointDto":{"type":"object","properties":{"lat":{"type":"number","example":6.3654},"lng":{"type":"number","example":2.4183}},"required":["lat","lng"]},"QuoteDto":{"type":"object","properties":{"pickupAddressId":{"type":"string","format":"uuid","description":"Adresse d'enlèvement enregistrée (ou `pickup`)"},"pickup":{"$ref":"#/components/schemas/PointDto"},"dropoff":{"description":"Absente : estimation par zone","allOf":[{"$ref":"#/components/schemas/PointDto"}]},"parcelSize":{"enum":["SMALL","MEDIUM","LARGE"],"type":"string"},"fragile":{"type":"object","default":false},"paymentMode":{"enum":["PREPAID","CASH_ON_DELIVERY"],"type":"string"},"goodsAmount":{"type":"object","default":0,"minimum":0,"maximum":10000000,"example":20000},"collection":{"enum":["SECURE","DIRECT"],"type":"string"}},"required":["parcelSize","paymentMode"]},"PartnerSurchargeDto":{"type":"object","properties":{"type":{"type":"string","enum":["LARGE_PARCEL","FRAGILE","NIGHT","RAIN","HIGH_DEMAND"]},"amount":{"type":"number","example":500}},"required":["type","amount"]},"PartnerQuoteDto":{"type":"object","properties":{"price":{"type":"number","example":1500,"description":"Prix de la course (FCFA)"},"isEstimate":{"type":"boolean","description":"Vrai si la destination est inconnue (estimation par zone)"},"base":{"type":"number","example":1500},"surcharges":{"type":"array","items":{"$ref":"#/components/schemas/PartnerSurchargeDto"}},"discount":{"type":"number","example":0},"codFee":{"type":"number","example":0,"description":"Frais d’encaissement retenus sur votre versement"},"fromZone":{"type":"string","nullable":true,"example":"Ganhi"},"toZone":{"type":"string","nullable":true,"example":"Godomey"}},"required":["price","isEstimate","base","surcharges","discount","codFee","fromZone","toZone"]},"ZoneMapEntryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Fidjrossè"},"city":{"type":"string","example":"Cotonou"},"shape":{"type":"array","description":"Contour simplifié : coordonnées d’un MultiPolygon GeoJSON [lng, lat], 5 décimales au plus","items":{"type":"array","items":{"type":"array","items":{"type":"array","items":{"type":"number"}}}},"example":[[[[2.38137,6.362],[2.38076,6.34635],[2.37413,6.347],[2.38137,6.362]]]]}},"required":["id","name","city","shape"]},"ZoneMapDto":{"type":"object","properties":{"bbox":{"nullable":true,"description":"Emprise [ouest, sud, est, nord] en degrés ; null sans zone active","example":[2.28,6.34,2.47,6.53],"type":"array","items":{"type":"number"}},"zones":{"type":"array","items":{"$ref":"#/components/schemas/ZoneMapEntryDto"}}},"required":["bbox","zones"]},"PartnerAddressDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string","nullable":true},"landmark":{"type":"string","nullable":true},"formatted":{"type":"string","nullable":true},"isDefault":{"type":"boolean"},"lat":{"type":"number"},"lng":{"type":"number"}},"required":["id","label","landmark","formatted","isDefault","lat","lng"]},"PlaceDto":{"type":"object","properties":{"lat":{"type":"number","example":6.3638},"lng":{"type":"number","example":2.3524},"label":{"type":"string","minLength":1,"maxLength":60,"example":"Domicile"},"landmark":{"type":"string","minLength":1,"maxLength":160,"example":"Portail vert après la mosquée"}},"required":["lat","lng"]},"CustomerDto":{"type":"object","properties":{"lastName":{"type":"string","minLength":1,"maxLength":80,"example":"Mensah"},"firstName":{"type":"string","minLength":1,"maxLength":80,"example":"Adjo"},"phone":{"type":"string","minLength":8,"maxLength":20,"example":"0197123456"}},"required":["lastName","firstName","phone"]},"ParcelDto":{"type":"object","properties":{"category":{"type":"string","minLength":2,"maxLength":40,"example":"FASHION"},"size":{"enum":["SMALL","MEDIUM","LARGE"],"type":"string"},"fragile":{"type":"object","default":false},"photoKey":{"type":"string","minLength":10,"maxLength":200,"description":"Clé renvoyée par POST /deliveries/parcel-photo/upload-url"}},"required":["category","size"]},"PaymentDto":{"type":"object","properties":{"mode":{"enum":["PREPAID","CASH_ON_DELIVERY"],"type":"string"},"goodsAmount":{"type":"object","default":0,"minimum":0,"maximum":10000000,"example":20000},"feePayer":{"default":"CUSTOMER","enum":["CUSTOMER","MERCHANT"],"type":"string"},"collection":{"enum":["SECURE","DIRECT"],"type":"string","description":"Défaut : réglage de la boutique"}},"required":["mode"]},"PartnerCreateDeliveryDto":{"type":"object","properties":{"pickupAddressId":{"type":"string","format":"uuid","description":"Adresse d'enlèvement enregistrée (ou `pickup`)"},"pickup":{"$ref":"#/components/schemas/PlaceDto"},"dropoff":{"description":"Absente : le client indiquera sa position","allOf":[{"$ref":"#/components/schemas/PlaceDto"}]},"customer":{"$ref":"#/components/schemas/CustomerDto"},"parcel":{"$ref":"#/components/schemas/ParcelDto"},"payment":{"$ref":"#/components/schemas/PaymentDto"},"instructions":{"type":"string","minLength":0,"maxLength":500},"promoCode":{"type":"string","minLength":0,"maxLength":40,"description":"Code promo (vérifié par POST /deliveries/promo/check)"},"externalRef":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[\\w.:/#-]+$","example":"WC-10482","description":"Numéro de la commande chez vous, unique par boutique"}},"required":["customer","parcel","payment"]},"PartnerCustomerDto":{"type":"object","properties":{"lastName":{"type":"string","example":"Dossou"},"firstName":{"type":"string","example":"Aïcha"},"phone":{"type":"string","example":"+2290197000000"}},"required":["lastName","firstName","phone"]},"PartnerPlaceDto":{"type":"object","properties":{"label":{"type":"string","nullable":true,"example":"Boutique"},"landmark":{"type":"string","nullable":true,"example":"À 40 m de Clinique Sainte Famille"},"lat":{"type":"number","example":6.3654},"lng":{"type":"number","example":2.4183}},"required":["label","landmark","lat","lng"]},"PartnerParcelDto":{"type":"object","properties":{"category":{"type":"string","example":"FASHION"},"size":{"type":"string","enum":["SMALL","MEDIUM","LARGE"]},"fragile":{"type":"boolean"}},"required":["category","size","fragile"]},"PartnerPaymentDto":{"type":"object","properties":{"mode":{"type":"string","enum":["PREPAID","CASH_ON_DELIVERY"]},"goodsAmount":{"type":"number","example":20000,"description":"Marchandise à encaisser (FCFA)"},"feePayer":{"type":"string","enum":["CUSTOMER","MERCHANT"]},"collection":{"type":"string","enum":["SECURE","DIRECT"]},"amountToCollect":{"type":"number","example":21500,"description":"Montant payé par le client à la livraison"},"status":{"type":"string","enum":["NOT_DUE","NOT_REQUESTED","AWAITING_CUSTOMER","AWAITING_MERCHANT","AWAITING_SENDER","PAID","FAILED","REFUSED"]},"paidAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["mode","goodsAmount","feePayer","collection","amountToCollect","status","paidAt"]},"PartnerCourierDto":{"type":"object","properties":{"firstName":{"type":"string","example":"Koffi"},"phone":{"type":"string","example":"+2290196000000"},"vehicleType":{"type":"string","enum":["MOTO","TRICYCLE","CAR"]},"plateNumber":{"type":"string","nullable":true,"example":"AB 1234"}},"required":["firstName","phone","vehicleType","plateNumber"]},"PartnerCreatedDeliveryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"reference":{"type":"string","example":"FX-522PDJ"},"externalRef":{"type":"string","nullable":true,"example":"WC-10482"},"status":{"type":"string","enum":["AWAITING_LOCATION","SEARCHING_COURIER","ASSIGNED","IN_TRANSIT","DELIVERED","FAILED","RETURNED","CANCELLED","EXPIRED"]},"createdAt":{"type":"string","format":"date-time"},"customer":{"$ref":"#/components/schemas/PartnerCustomerDto"},"pickup":{"$ref":"#/components/schemas/PartnerPlaceDto"},"dropoff":{"nullable":true,"description":"Absente tant que le client n’a pas indiqué sa position","type":"object","allOf":[{"$ref":"#/components/schemas/PartnerPlaceDto"}]},"parcel":{"$ref":"#/components/schemas/PartnerParcelDto"},"payment":{"$ref":"#/components/schemas/PartnerPaymentDto"},"price":{"type":"number","example":1500,"description":"Prix de la course (FCFA)"},"priceIsEstimate":{"type":"boolean","description":"Vrai tant que la destination n’est pas connue"},"cancellationFee":{"type":"number","example":0},"returnFee":{"type":"number","example":0},"failureReason":{"type":"string","nullable":true,"example":null},"courier":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/PartnerCourierDto"}]},"pickupCode":{"type":"string","nullable":true,"example":"4827","description":"Code d’enlèvement à donner au livreur ; renvoyé seulement à la création"}},"required":["id","reference","externalRef","status","createdAt","customer","pickup","dropoff","parcel","payment","price","priceIsEstimate","cancellationFee","returnFee","failureReason","courier","pickupCode"]},"Object":{"type":"object","properties":{}},"PartnerDeliveryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"reference":{"type":"string","example":"FX-522PDJ"},"externalRef":{"type":"string","nullable":true,"example":"WC-10482"},"status":{"type":"string","enum":["AWAITING_LOCATION","SEARCHING_COURIER","ASSIGNED","IN_TRANSIT","DELIVERED","FAILED","RETURNED","CANCELLED","EXPIRED"]},"createdAt":{"type":"string","format":"date-time"},"customer":{"$ref":"#/components/schemas/PartnerCustomerDto"},"pickup":{"$ref":"#/components/schemas/PartnerPlaceDto"},"dropoff":{"nullable":true,"description":"Absente tant que le client n’a pas indiqué sa position","type":"object","allOf":[{"$ref":"#/components/schemas/PartnerPlaceDto"}]},"parcel":{"$ref":"#/components/schemas/PartnerParcelDto"},"payment":{"$ref":"#/components/schemas/PartnerPaymentDto"},"price":{"type":"number","example":1500,"description":"Prix de la course (FCFA)"},"priceIsEstimate":{"type":"boolean","description":"Vrai tant que la destination n’est pas connue"},"cancellationFee":{"type":"number","example":0},"returnFee":{"type":"number","example":0},"failureReason":{"type":"string","nullable":true,"example":null},"courier":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/PartnerCourierDto"}]}},"required":["id","reference","externalRef","status","createdAt","customer","pickup","dropoff","parcel","payment","price","priceIsEstimate","cancellationFee","returnFee","failureReason","courier"]},"PartnerDeliveryPageDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PartnerDeliveryDto"}},"total":{"type":"number","example":42},"page":{"type":"number","example":1},"pageSize":{"type":"number","example":30}},"required":["items","total","page","pageSize"]},"PartnerEventDto":{"type":"object","properties":{"status":{"type":"string","enum":["AWAITING_LOCATION","SEARCHING_COURIER","ASSIGNED","IN_TRANSIT","DELIVERED","FAILED","RETURNED","CANCELLED","EXPIRED"]},"note":{"type":"string","nullable":true},"occurredAt":{"type":"string","format":"date-time"}},"required":["status","note","occurredAt"]},"CancelDto":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":200}}}}}}