{"openapi":"3.0.3","info":{"title":"ReachFlow API publique","version":"1.0.0","description":"API REST v1 — messages transactionnels WhatsApp, OTP, providers. Authentification : en-tête X-API-Key."},"servers":[{"url":"/api/v1","description":"Instance ReachFlow"}],"tags":[{"name":"Providers","description":"Numéros WhatsApp (channel_providers) connectés."},{"name":"Messages","description":"Envoi transactionnel et statut."},{"name":"OTP","description":"Codes à usage unique par WhatsApp."}],"paths":{"/providers":{"get":{"tags":["Providers"],"operationId":"listProviders","summary":"Lister tous les providers","description":"Retourne la liste des numéros WhatsApp de votre organisation accessibles via l’API.","x-reachflow-id":"list-all-providers","x-reachflow-scope":"providers:read","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Liste des providers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProviderList"},"example":{"providers":[{"id":"a3f1b2c4-1234-4abc-9def-000011112222","name":"Support client","phoneNumber":"22997000000","status":"connected","warmupDay":14,"riskScore":12}]}}}}}}},"/providers/{id}":{"get":{"tags":["Providers"],"operationId":"getProvider","summary":"Afficher un provider","description":"Détail d’un provider avec statistiques journalières.","x-reachflow-id":"get-provider","x-reachflow-scope":"providers:read","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Identifiant du provider."}],"responses":{"200":{"description":"Provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProviderDetail"}}}}}}},"/messages/send":{"post":{"tags":["Messages"],"operationId":"sendMessage","summary":"Envoyer un message texte","description":"Met en file un message texte vers un destinataire. Le provider doit être connecté.","x-reachflow-id":"send-message","x-reachflow-scope":"messages:send","security":[{"ApiKey":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Clé d’idempotence optionnelle."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSendMessage"},"example":{"providerId":"a3f1b2c4-1234-4abc-9def-000011112222","to":"22996123456","message":"Bonjour depuis ReachFlow !"}}}},"responses":{"202":{"description":"Message accepté en file","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSendAccepted"}}}}}}},"/messages/send-media":{"post":{"tags":["Messages"],"operationId":"sendMedia","summary":"Envoyer un média","description":"Envoie une image, vidéo, audio ou document via URL publique.","x-reachflow-id":"send-media","x-reachflow-scope":"messages:send","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSendMedia"},"example":{"providerId":"a3f1b2c4-1234-4abc-9def-000011112222","to":"22996123456","mediaUrl":"https://example.com/photo.jpg","mediaType":"image","caption":"Votre reçu"}}}},"responses":{"202":{"description":"Message accepté","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSendAccepted"}}}}}}},"/messages/send-bulk":{"post":{"tags":["Messages"],"operationId":"sendBulk","summary":"Envoi en lot","description":"Envoie le même modèle à plusieurs destinataires. Les refus partiels sont listés dans rejections.","x-reachflow-id":"send-bulk","x-reachflow-scope":"messages:send","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSendBulk"}}}},"responses":{"200":{"description":"Résultat du lot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSendBulkResponse"}}}}}}},"/messages/{id}":{"get":{"tags":["Messages"],"operationId":"getMessageStatus","summary":"Statut d’un message","description":"Consulte le cycle de vie d’un message API précédemment accepté.","x-reachflow-id":"get-message-status","x-reachflow-scope":"messages:read","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Identifiant message (messageId)."}],"responses":{"200":{"description":"Statut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicMessageStatus"}}}}}}},"/otp/send":{"post":{"tags":["OTP"],"operationId":"sendOtp","summary":"Envoyer un OTP","description":"Génère un code et l’envoie au numéro indiqué. Par défaut le message utilise le nom du tenant (`{{brand}}`) ; `brandName` permet de le surcharger (marque de votre app).","x-reachflow-id":"send-otp","x-reachflow-scope":"otp:send","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicOtpSend"},"example":{"providerId":"a3f1b2c4-1234-4abc-9def-000011112222","phoneNumber":"22996123456","brandName":"Mon App","codeLength":6,"expiresIn":300}}}},"responses":{"200":{"description":"OTP créé","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicOtpSendResponse"}}}}}}},"/otp/verify":{"post":{"tags":["OTP"],"operationId":"verifyOtp","summary":"Vérifier un OTP","description":"Valide le code saisi par l’utilisateur final.","x-reachflow-id":"verify-otp","x-reachflow-scope":"otp:verify","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicOtpVerify"},"example":{"otpId":"c4d5e6f7-8901-42ab-cdef-333344445555","code":"482910"}}}},"responses":{"200":{"description":"Résultat de vérification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicOtpVerifyResponse"},"example":{"valid":true}}}}}}}},"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Clé API live ou test (dashboard → API → Clés API)."}},"schemas":{"PublicSendMessage":{"type":"object","required":["providerId","to","message"],"properties":{"providerId":{"type":"string","format":"uuid","description":"Provider expéditeur."},"to":{"type":"string","description":"Numéro destinataire (8–20 car.)."},"message":{"type":"string","description":"Corps du message (1–4096 car.)."},"variables":{"type":"object","additionalProperties":{"type":"string"},"description":"Variables pour modèle {{clé}}."},"scheduleAt":{"type":"string","format":"date-time","description":"Envoi différé optionnel."},"saveContact":{"type":"boolean","default":false,"description":"Si true, enregistre le destinataire dans la base contacts (find-or-create). Par défaut : envoi direct sans création ni quota contacts."}}},"PublicSendMedia":{"type":"object","required":["providerId","to","mediaUrl","mediaType"],"properties":{"providerId":{"type":"string","format":"uuid"},"to":{"type":"string"},"mediaUrl":{"type":"string","format":"uri"},"mediaType":{"enum":["image","document","audio","video"]},"caption":{"type":"string"},"saveContact":{"type":"boolean","default":false}}},"PublicSendBulk":{"type":"object","required":["providerId","messageTemplate","recipients"],"properties":{"providerId":{"type":"string","format":"uuid"},"messageTemplate":{"type":"string"},"recipients":{"type":"array","items":{"type":"object","required":["to"],"properties":{"to":{"type":"string"},"variables":{"type":"object","additionalProperties":{"type":"string"}}}}},"scheduleAt":{"type":"string","format":"date-time"},"saveContact":{"type":"boolean","default":false}}},"PublicSendAccepted":{"type":"object","properties":{"messageId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued"]},"queuedAt":{"type":"string","format":"date-time"}}},"PublicSendBulkResponse":{"type":"object","properties":{"bulkId":{"type":"string","format":"uuid"},"accepted":{"type":"integer"},"rejected":{"type":"integer"},"rejections":{"type":"array","items":{"type":"object"}},"messageIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"PublicMessageStatus":{"type":"object","properties":{"messageId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","processing","sent","delivered","failed","cancelled"]},"to":{"type":"string"},"providerId":{"type":"string","format":"uuid"},"queuedAt":{"type":"string","format":"date-time"},"sentAt":{"type":"string","format":"date-time","nullable":true},"deliveredAt":{"type":"string","format":"date-time","nullable":true},"failedAt":{"type":"string","format":"date-time","nullable":true},"failureCode":{"type":"string","nullable":true},"failureReason":{"type":"string","nullable":true}}},"PublicProviderList":{"type":"object","properties":{"providers":{"type":"array","items":{"$ref":"#/components/schemas/PublicProviderSummary"}}}},"PublicProviderSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phoneNumber":{"type":"string","nullable":true},"status":{"type":"string"},"warmupDay":{"type":"integer"},"riskScore":{"type":"integer"}}},"PublicProviderDetail":{"allOf":[{"$ref":"#/components/schemas/PublicProviderSummary"},{"type":"object","properties":{"dailyStats":{"type":"object"}}}]},"PublicOtpSend":{"type":"object","required":["providerId","phoneNumber"],"properties":{"providerId":{"type":"string","format":"uuid"},"phoneNumber":{"type":"string"},"codeLength":{"type":"integer","default":6},"expiresIn":{"type":"integer","default":300},"brandName":{"type":"string","maxLength":64,"description":"Nom affiché dans le message (marque de votre application). Si omis : nom de l’organisation ReachFlow du tenant."},"template":{"type":"string","description":"Modèle personnalisé. Placeholders : {{brand}}, {{code}}. Défaut : « Votre code de vérification {{brand}} : {{code}} »."},"saveContact":{"type":"boolean","default":false}}},"PublicOtpSendResponse":{"type":"object","properties":{"otpId":{"type":"string","format":"uuid"},"messageId":{"type":"string","format":"uuid","description":"Message WhatsApp en file — le code n’est pas renvoyé par l’API (voir statut sent/failed)."},"expiresAt":{"type":"string","format":"date-time"}}},"PublicOtpVerify":{"type":"object","required":["otpId","code"],"properties":{"otpId":{"type":"string","format":"uuid"},"code":{"type":"string"}}},"PublicOtpVerifyResponse":{"type":"object","properties":{"valid":{"type":"boolean"},"reason":{"type":"string"},"attemptsLeft":{"type":"integer"}}}}}}