API — Référence v1¶
Introduction¶
L'API SalamBot v1 permet l'intégration serveur-serveur et l'accès aux canaux (webchat, sociaux) via un modèle d'envelope unifié.
Pour les détails sur l'envelope et les composants : Concepts/composants.
Base URL & Versionnage¶
| Clé | Valeur |
|---|---|
| base_url | https://api.salambot.local/v1 |
| version | v1 |
| content_type | application/json; charset=utf-8 |
| charset | utf-8 |
Authentification & En-têtes¶
Support : Bearer OIDC/JWT.
En-têtes recommandés :
| En-tête | Valeur |
|---|---|
| Authorization | Bearer <token> |
| X-SalamBot-Tenant | <tenant> |
| Idempotency-Key | <uuid> |
| X-Request-Id | <uuid> |
Scopes (si activés) :
| scope | usage |
|---|---|
| messages:analyze | NLU |
| search:query | RAG |
| generate:reply | LLM Router |
| incidents:write | Incidents |
| tickets:write | Tickets |
| admin:read | Lecture policies |
| admin:write | Mise à jour policies |
Flux d'authentification JWT¶
Le diagramme suivant illustre le processus d'authentification complet avec gestion des refresh tokens :
sequenceDiagram
participant C as Client
participant API as API Gateway
participant AUTH as Service Auth
participant OIDC as Provider OIDC
participant CACHE as Cache Redis
Note over C,CACHE: Authentification initiale
C->>AUTH: POST /auth/login<br/>{username, password}
AUTH->>OIDC: Validation credentials
OIDC-->>AUTH: User claims + scopes
AUTH->>AUTH: Génération JWT + refresh token
AUTH->>CACHE: Store refresh token (TTL 7d)
AUTH-->>C: {access_token, refresh_token, expires_in}
Note over C,CACHE: Requête API avec token
C->>API: GET /v1/messages/analyze<br/>Authorization: Bearer <jwt>
API->>API: Validation JWT signature
API->>API: Vérification expiration
alt Token valide
API->>API: Extraction claims (tenant, scopes)
API->>API: Vérification scope messages:analyze
API-->>C: 200 OK + données
else Token expiré
API-->>C: 401 Unauthorized<br/>{error: "token_expired"}
else Token invalide
API-->>C: 401 Unauthorized<br/>{error: "invalid_token"}
end
Note over C,CACHE: Refresh du token
C->>AUTH: POST /auth/refresh<br/>{refresh_token}
AUTH->>CACHE: Validation refresh token
alt Refresh token valide
AUTH->>AUTH: Génération nouveau JWT
AUTH->>CACHE: Rotation refresh token
AUTH-->>C: {access_token, refresh_token, expires_in}
else Refresh token expiré/invalide
AUTH->>CACHE: Suppression token
AUTH-->>C: 401 Unauthorized<br/>{error: "refresh_required"}
Note over C: Redirection vers login
end
Note over C,CACHE: Logout
C->>AUTH: POST /auth/logout<br/>{refresh_token}
AUTH->>CACHE: Blacklist refresh token
AUTH-->>C: 200 OK
Envelope de requête/réponse¶
Toutes les requêtes et réponses utilisent l'envelope unifié :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_123",
"correlation_id": "corr_abc",
"timestamp": "2025-08-14T10:30:00Z",
"locale": "fr-MA",
"data": {
"NOTE": "payload spécifique à l'endpoint"
}
}
Conventions :
- Champs temporels en RFC3339
- Nommage en snake_case
Erreurs & modèle d'erreur¶
Mapping erreurs ↔ HTTP :
| erreur | http |
|---|---|
| invalid_input | 400 |
| unauthorized | 401 |
| permission_denied | 403 |
| rate_limited | 429 |
| internal_error | 500 |
| upstream_error | 502 |
| timeout | 504 |
Modèle d'erreur :
{
"schema_version": "1.0",
"error": "invalid_input",
"http": 400,
"message": "Champ 'data.text' requis",
"correlation_id": "corr_abc"
}
Gestion des erreurs et retry logic¶
Le diagramme suivant illustre la stratégie de retry différenciée selon le type d'erreur :
flowchart TD
REQ[Requête API] --> EXEC[Exécution]
EXEC --> SUCCESS{Succès?}
SUCCESS -->|Oui| OK[200-299: Retour résultat]
SUCCESS -->|Non| ERROR{Type d'erreur?}
ERROR -->|400-499| CLIENT[Erreur client]
ERROR -->|500-599| SERVER[Erreur serveur]
ERROR -->|Timeout| TIMEOUT[Timeout réseau]
CLIENT --> CHECK_400{Code spécifique?}
CHECK_400 -->|400 invalid_input| NO_RETRY[❌ Pas de retry<br/>Corriger payload]
CHECK_400 -->|401 unauthorized| AUTH_RETRY{Token refresh?}
CHECK_400 -->|403 permission_denied| NO_RETRY
CHECK_400 -->|429 rate_limited| RATE_RETRY[⏱️ Retry avec backoff<br/>Délai = Retry-After header]
AUTH_RETRY -->|Possible| REFRESH[Refresh token]
AUTH_RETRY -->|Impossible| NO_RETRY
REFRESH --> SUCCESS_REFRESH{Refresh OK?}
SUCCESS_REFRESH -->|Oui| RETRY_AUTH[🔄 Retry requête originale]
SUCCESS_REFRESH -->|Non| NO_RETRY
SERVER --> CHECK_500{Code spécifique?}
CHECK_500 -->|500 internal_error| RETRY_EXP[🔄 Retry exponentiel<br/>Max 3 tentatives]
CHECK_500 -->|502 upstream_error| RETRY_EXP
CHECK_500 -->|503 service_unavailable| RETRY_LINEAR[🔄 Retry linéaire<br/>Délai fixe 5s]
CHECK_500 -->|504 timeout| RETRY_EXP
TIMEOUT --> RETRY_EXP
RATE_RETRY --> WAIT_RATE[Attendre délai]
WAIT_RATE --> RETRY_AUTH
RETRY_EXP --> COUNT_EXP{Tentatives < 3?}
COUNT_EXP -->|Oui| BACKOFF_EXP[Backoff: 2^n * 1s<br/>n = tentative]
COUNT_EXP -->|Non| FAIL[❌ Échec définitif]
BACKOFF_EXP --> RETRY_AUTH
RETRY_LINEAR --> COUNT_LIN{Tentatives < 5?}
COUNT_LIN -->|Oui| BACKOFF_LIN[Attendre 5s]
COUNT_LIN -->|Non| FAIL
BACKOFF_LIN --> RETRY_AUTH
RETRY_AUTH --> EXEC
style OK fill:#4caf50
style NO_RETRY fill:#f44336
style FAIL fill:#f44336
style RETRY_EXP fill:#ff9800
style RETRY_LINEAR fill:#ff9800
style RATE_RETRY fill:#2196f3
Rate limiting & Idempotency¶
| Clé | Valeur |
|---|---|
| rate_limit_unit | requests/min |
| rate_limit_scope | per-tenant + per-channel |
| rate_limit_headers | X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset |
| retry-after | sur 429 (en secondes) |
| idempotency | Idempotency-Key sur POST |
| idempotency_scope | par (tenant, channel, message_id), fenêtre 24h |
| idempotency_behavior | si même clé: retour premier résultat (HTTP 201/200), sinon 409 conflit payload |
Endpoints¶
Tous les endpoints suivent le pattern /v1/{service}/{action} avec
authentification Bearer JWT.
Endpoints canoniques¶
- Génération :
POST /v1/generate/reply - Recherche RAG :
POST /v1/search/query
Toute autre variante est dépréciée. Les exemples et SDK doivent s'aligner sur ces chemins.
Endpoints — NLU (Messages)¶
POST /v1/messages/analyze¶
Analyse le texte utilisateur pour extraire l'intention, les entités et la confiance. Utilisé pour le routage intelligent des messages.
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_123",
"correlation_id": "corr_abc",
"timestamp": "2025-08-14T10:30:00Z",
"locale": "fr-MA",
"data": {
"text": "Je veux annuler ma commande",
"lang": "fr"
}
}
Response :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_123",
"correlation_id": "corr_abc",
"timestamp": "2025-08-14T10:30:01Z",
"locale": "fr-MA",
"data": {
"intent": "cancel_order",
"confidence": 0.92,
"entities": [
{ "type": "action", "value": "annuler", "start": 8, "end": 15 }
]
}
}
Exemple cURL :
curl -X POST https://api.salambot.local/v1/messages/analyze \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Content-Type: application/json" \
-H "X-SalamBot-Tenant: acme" \
-d '{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_123",
"correlation_id": "corr_abc",
"timestamp": "2025-08-14T10:30:00Z",
"locale": "fr-MA",
"data": {
"text": "Je veux annuler ma commande",
"lang": "fr"
}
}'
Codes : 200, 400, 401, 429, 500
POST /v1/generate/stream¶
Stream SSE de la réponse LLM (recommandé pour Webchat). Contenu:
text/event-stream.
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_789",
"correlation_id": "corr_ghi",
"timestamp": "2025-08-14T10:34:00Z",
"locale": "fr-MA",
"data": {
"prompt": "Comment puis-je annuler ma commande ?",
"context": [
"L'utilisateur a une commande active #12345",
"Politique: annulation possible sous 24h"
],
"model": "llama3"
}
}
Réponse (SSE) :
event: token
data: {"text":"Pour annuler ","seq":1}
event: token
data: {"text":"votre commande...","seq":2}
event: done
data: {"model_used":"llama3","tokens":156,"confidence":0.94}
Exemple cURL :
curl -N -X POST https://api.salambot.local/v1/generate/stream \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_789",
"correlation_id": "corr_ghi",
"timestamp": "2025-08-14T10:34:00Z",
"locale": "fr-MA",
"data": {
"prompt": "Comment puis-je annuler ma commande ?",
"context": ["commande #12345"],
"model": "llama3"
}
}'
Codes : 200 (SSE), 400, 401, 429, 500
Endpoints — Recherche (RAG)¶
POST /v1/search/query¶
Recherche contextuelle dans la base de connaissances. Retourne les passages les plus pertinents avec scores de similarité.
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_456",
"correlation_id": "corr_def",
"timestamp": "2025-08-14T10:32:00Z",
"locale": "fr-MA",
"data": {
"query": "politique de remboursement",
"filters": { "category": "support" },
"limit": 5
}
}
Response :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_456",
"correlation_id": "corr_def",
"timestamp": "2025-08-14T10:32:01Z",
"locale": "fr-MA",
"data": {
"passages": [
"Les remboursements sont traités sous 7 jours...",
"Pour demander un remboursement, contactez..."
],
"ids": ["doc_123", "doc_456"],
"scores": [0.89, 0.76]
}
}
Exemple cURL :
curl -X POST https://api.salambot.local/v1/search/query \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_456",
"correlation_id": "corr_def",
"timestamp": "2025-08-14T10:32:00Z",
"locale": "fr-MA",
"data": {
"query": "politique de remboursement",
"filters": {"category": "support"},
"limit": 5
}
}'
Codes : 200, 400, 401, 429, 500, 502
Endpoints — Génération (LLM Router)¶
POST /v1/generate/reply¶
Génère une réponse contextuelle via LLM. Route automatiquement vers le modèle optimal selon le contexte.
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_789",
"correlation_id": "corr_ghi",
"timestamp": "2025-08-14T10:34:00Z",
"locale": "fr-MA",
"data": {
"prompt": "Comment puis-je annuler ma commande ?",
"context": [
"L'utilisateur a une commande active #12345",
"Politique: annulation possible sous 24h"
],
"model": "llama3"
}
}
Response :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_789",
"correlation_id": "corr_ghi",
"timestamp": "2025-08-14T10:34:02Z",
"locale": "fr-MA",
"data": {
"reply_text": "Pour annuler votre commande #12345, vous pouvez...",
"model_used": "llama3",
"tokens": 156,
"confidence": 0.94,
"filtered": false
}
}
Exemple cURL :
curl -X POST https://api.salambot.local/v1/generate/reply \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_789",
"correlation_id": "corr_ghi",
"timestamp": "2025-08-14T10:34:00Z",
"locale": "fr-MA",
"data": {
"prompt": "Comment puis-je annuler ma commande ?",
"context": ["L'utilisateur a une commande active #12345"],
"model": "llama3"
}
}'
Codes : 200, 400, 401, 429, 500
Endpoints — Incidents & Broadcast¶
POST /v1/incidents¶
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "system",
"message_id": "msg_inc1",
"correlation_id": "corr_inc",
"timestamp": "2025-08-14T10:36:00Z",
"locale": "fr-MA",
"data": {
"trigger": "Panne serveur principal",
"severity": "high",
"details": {
"affected_services": ["webchat", "api"],
"estimated_impact": "30min"
}
}
}
Response :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "system",
"message_id": "msg_inc1",
"correlation_id": "corr_inc",
"timestamp": "2025-08-14T10:36:01Z",
"locale": "fr-MA",
"data": {
"ticket_id": "INC-2025-001",
"status": "assigned",
"assignee": "ops-team"
}
}
Codes : 201, 400, 401, 403, 429, 500
POST /v1/broadcasts¶
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "admin",
"message_id": "msg_bcast",
"correlation_id": "corr_bcast",
"timestamp": "2025-08-14T10:38:00Z",
"locale": "fr-MA",
"data": {
"message": "Maintenance programmée ce soir 22h-23h",
"audience": "all_users",
"schedule": "2025-08-14T20:00:00Z"
}
}
Response :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "admin",
"message_id": "msg_bcast",
"correlation_id": "corr_bcast",
"timestamp": "2025-08-14T10:38:01Z",
"locale": "fr-MA",
"data": {
"event": "broadcast_scheduled",
"recipients": 1250,
"status": "pending"
}
}
Codes : 202, 400, 401, 403, 429, 500
Endpoints — Tickets¶
POST /v1/tickets¶
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_tkt",
"correlation_id": "corr_tkt",
"timestamp": "2025-08-14T10:40:00Z",
"locale": "fr-MA",
"data": {
"incident": "Problème complexe non résolu",
"user_context": {
"id": "user_123",
"history": ["previous_interactions"]
},
"priority": "high"
}
}
Response :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "webchat",
"message_id": "msg_tkt",
"correlation_id": "corr_tkt",
"timestamp": "2025-08-14T10:40:01Z",
"locale": "fr-MA",
"data": {
"ticket_id": "TKT-2025-456",
"status": "assigned",
"eta_hours": 2
}
}
Codes : 201, 400, 401, 403, 429, 500
Endpoints — Admin¶
GET /v1/admin/policies¶
Response :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "admin",
"message_id": "msg_pol_get",
"correlation_id": "corr_pol",
"timestamp": "2025-08-14T10:42:00Z",
"locale": "fr-MA",
"data": {
"policies": {
"max_tokens": 1000,
"allowed_models": ["llama3"],
"branding": {
"logo_url": "https://cdn.example.com/logo.png",
"colors": "#123456"
}
}
}
}
Codes : 200, 401, 403, 500
PUT /v1/admin/policies¶
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "admin",
"message_id": "msg_pol_put",
"correlation_id": "corr_pol_upd",
"timestamp": "2025-08-14T10:44:00Z",
"locale": "fr-MA",
"data": {
"policies": {
"max_tokens": 1500,
"allowed_models": ["llama3", "gpt-4"]
}
}
}
Response :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "admin",
"message_id": "msg_pol_put",
"correlation_id": "corr_pol_upd",
"timestamp": "2025-08-14T10:44:01Z",
"locale": "fr-MA",
"data": {
"ack": true,
"version": "v2.1",
"applied_at": "2025-08-14T10:44:01Z"
}
}
Exemple cURL :
curl -X PUT https://api.salambot.local/v1/admin/policies \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Content-Type: application/json" \
-d '{
"schema_version": "1.0",
"tenant": "acme",
"channel": "admin",
"message_id": "msg_pol_put",
"correlation_id": "corr_pol_upd",
"timestamp": "2025-08-14T10:44:00Z",
"locale": "fr-MA",
"data": {
"policies": {
"max_tokens": 1500,
"allowed_models": ["llama3", "gpt-4"]
}
}
}'
Codes : 200, 400, 401, 403, 429, 500
Healthcheck¶
GET /v1/health¶
Response :
{
"schema_version": "1.0",
"data": {
"status": "ok",
"time": "2025-08-14T10:46:00Z"
}
}
Codes : 200
GET /v1/ready¶
Response :
{
"schema_version": "1.0",
"data": {
"status": "ready",
"deps": {
"database": "ok",
"redis": "ok",
"llm_service": "ok"
}
}
}
Codes : 200, 503
Webhooks & HMAC (source unique)¶
En-têtes requis¶
X-Hub-Signature-256:sha256=<hex>(HMAC-SHA256 du payload brut)X-Request-Id: UUID (minuscule)X-SalamBot-Tenant: identifiant tenantX-Timestamp: ISO 8601 UTCZ(ex:2025-08-14T10:30:00Z)
Fenêtre temporelle & idempotence¶
- Tolérance horloge : ±5 min (refus au-delà)
- Idempotence : dédupliquer via
event_idou hash du corps 24h
Génération de la signature (éditeur tiers)¶
sha256 = HMAC_SHA256(secret, raw_body)
header = "sha256=" + hex(sha256)
Vérification (Python)¶
import hmac, hashlib
sig_hdr = req.headers['X-Hub-Signature-256']
calc = 'sha256=' + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
assert hmac.compare_digest(calc, sig_hdr)
Réponses & retries¶
- 2xx : accepté (pas de retry)
- 4xx : invalide (no retry)
- 5xx : retry exponentiel jusqu'à 5 tentatives (2s,4s,8s,16s,32s)
Exemples cURL¶
curl -X POST "$PUBLIC/webhooks/<canal>" \
-H "Content-Type: application/json" \
-H "X-Request-Id: $(uuidgen | tr 'A-Z' 'a-z')" \
-H "X-SalamBot-Tenant: demo" \
-H "X-Timestamp: 2025-08-14T10:30:00Z" \
-H "X-Hub-Signature-256: sha256=<...>" \
--data-binary @payload.json
Les documents
Security/iam.md,Security/pii.md,Security/audit.mdréférencent cette section pour éviter les doublons.
Exemples d'ingestion par canal¶
POST /webhooks/facebook¶
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "facebook",
"message_id": "msg_fb",
"correlation_id": "corr_fb",
"timestamp": "2025-08-14T10:48:00Z",
"locale": "fr-MA",
"data": {
"webhook_data": {
"object": "page",
"entry": [
{
"messaging": [
{
"sender": { "id": "123" },
"message": { "text": "Bonjour" }
}
]
}
]
}
}
}
Response : 202 Accepted
POST /webhooks/whatsapp¶
Request :
{
"schema_version": "1.0",
"tenant": "acme",
"channel": "whatsapp",
"message_id": "msg_wa",
"correlation_id": "corr_wa",
"timestamp": "2025-08-14T10:50:00Z",
"locale": "fr-MA",
"data": {
"webhook_data": {
"contacts": [{ "profile": { "name": "John" } }],
"messages": [{ "text": { "body": "Salut" } }]
}
}
}
Response : 202 Accepted
Pagination & filtres¶
Paramètres standards :
| Paramètre | Valeur |
|---|---|
| page | int |
| page_size | 1..100 |
| sort | created_at:desc |
| filter | k:v |
Exemples cURL groupés¶
NLU :
curl -X POST https://api.salambot.local/v1/messages/analyze \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"schema_version":"1.0","tenant":"acme","channel":"webchat","message_id":"msg_123","correlation_id":"corr_abc","timestamp":"2025-08-14T10:30:00Z","locale":"fr-MA","data":{"text":"Je veux annuler","lang":"fr"}}'
RAG :
curl -X POST https://api.salambot.local/v1/search/query \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"schema_version":"1.0","tenant":"acme","channel":"webchat","message_id":"msg_456","correlation_id":"corr_def","timestamp":"2025-08-14T10:32:00Z","locale":"fr-MA","data":{"query":"remboursement","limit":5}}'
LLM :
curl -X POST https://api.salambot.local/v1/generate/reply \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"schema_version":"1.0","tenant":"acme","channel":"webchat","message_id":"msg_789","correlation_id":"corr_ghi","timestamp":"2025-08-14T10:34:00Z","locale":"fr-MA","data":{"prompt":"Comment annuler ?","context":["commande #12345"],"model":"llama3"}}'
Tickets :
curl -X POST https://api.salambot.local/v1/tickets \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"schema_version":"1.0","tenant":"acme","channel":"webchat","message_id":"msg_tkt","correlation_id":"corr_tkt","timestamp":"2025-08-14T10:40:00Z","locale":"fr-MA","data":{"incident":"Problème complexe","priority":"high"}}'
Admin :
curl -X GET https://api.salambot.local/v1/admin/policies \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json"
Endpoints — Admin¶
POST /v1/admin/channels¶
Active un canal pour un tenant donné. Utilisé lors de l'onboarding.
Request :
{
"schema_version": "1.0",
"tenant": "nouveau-tenant",
"channel": "admin",
"message_id": "msg_channel_setup",
"correlation_id": "corr_channel_setup",
"timestamp": "2025-08-14T10:30:00Z",
"locale": "fr-MA",
"data": {
"tenant": "nouveau-tenant",
"channel": "facebook",
"config": {
"page_access_token": "...",
"verify_token": "..."
}
}
}
Response :
{
"schema_version": "1.0",
"tenant": "nouveau-tenant",
"channel": "admin",
"message_id": "msg_channel_setup",
"correlation_id": "corr_channel_setup",
"timestamp": "2025-08-14T10:30:01Z",
"locale": "fr-MA",
"data": {
"status": "activated",
"channel": "facebook",
"webhook_url": "https://api.salambot.local/webhooks/facebook"
}
}
Exemple cURL :
curl -X POST https://api.salambot.local/v1/admin/channels \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-H "X-SalamBot-Tenant: nouveau-tenant" \
-d '{
"schema_version": "1.0",
"tenant": "nouveau-tenant",
"channel": "admin",
"message_id": "msg_channel_setup",
"correlation_id": "corr_channel_setup",
"timestamp": "2025-08-14T10:30:00Z",
"locale": "fr-MA",
"data": {
"tenant": "nouveau-tenant",
"channel": "facebook",
"config": {
"page_access_token": "...",
"verify_token": "..."
}
}
}'
Codes : 201, 400, 401, 403, 409, 500
Changelog API¶
| Version | Description |
|---|---|
| v1.0 | endpoints initiaux |
| date | 2025-08-14 |
Time & IDs — Normes API¶
- Horodatage : ISO-8601 strict en UTC avec suffixe
Z(ex.2025-08-14T10:30:00.123Z). L'affichage local (UTC+1) est UI seulement. - Corrélation : propager
trace_id,span_id,correlation_id,X-Request-Idà chaque hop ; corrélation SIEM surtrace_id/correlation_id. - Idempotence :
POSTcritiques exigentIdempotency-Keyunique (TTL ≥ 24h) pour éviter les doublons. - Endpoints canoniques : n'utiliser que
/v1/generate/replyet/v1/search/querydans cette référence (les variantes sont dépréciées).