API REST v1

Documentation de l'API

Envoyez des messages WhatsApp depuis votre application via une API REST simple. Authentification par clé, réponses JSON, codes HTTP standards.

Base URL : https://winochat.ma/api/v1

Authentification

Chaque requête doit inclure votre clé API dans l'en-tête Authorization, selon le schéma Bearer :

Authorization: Bearer wch_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

En alternative, l'en-tête X-API-Key est accepté.

Vos clés se gèrent depuis votre espace : Tenant → Clés API. Une clé n'est affichée en clair qu'une seule fois, à sa création.

Ne partagez jamais votre clé et ne l'exposez pas côté navigateur. Gardez-la côté serveur.

Envoyer un message

POST/api/v1/messages

Paramètres (corps JSON)

ChampTypeRequisDescription
tostringouiNuméro du destinataire. Format local (0600000000) ou international (212600000000).
bodystringouiContenu texte du message.
typestringnonType de message. Défaut : text.
referencestringnonRéférence libre côté client, renvoyée telle quelle.

Exemple de requête

curl -X POST https://winochat.ma/api/v1/messages \
  -H "Authorization: Bearer wch_VOTRE_CLE_API" \
  -H "Content-Type: application/json" \
  -d '{"to":"0600000000","body":"Bonjour !","type":"text"}'

Réponse — succès (201)

// 201 Created — message accepté et mis en file
{
  "data": {
    "id": 8,
    "status": "queued",
    "to": "212600000110",
    "type": "text",
    "price": 0.08,
    "balance_after": 285.36,
    "reference": "votre-reference",
    "queued_at": "2026-05-30T20:33:58+01:00"
  }
}
Le statut queued signifie « accepté et en file ». L'envoi réel suit immédiatement. Suivez la remise via le statut du message ou les webhooks.

Statut d'un message

GET/api/v1/messages/{id}/status

curl https://winochat.ma/api/v1/messages/8/status \
  -H "Authorization: Bearer wch_VOTRE_CLE_API"
{
  "data": {
    "id": 8,
    "status": "sent",
    "sent_at": "2026-05-30T20:34:02+01:00",
    "error_message": null
  }
}

Statuts : queued, sent, failed (voir error_message).

Consulter le solde

GET/api/v1/balance

curl https://winochat.ma/api/v1/balance \
  -H "Authorization: Bearer wch_VOTRE_CLE_API"
{
  "data": {
    "balance": 285.36,
    "currency": "MAD",
    "price_per_message": 0.08
  }
}

Statistiques

GET/api/v1/stats

Renvoie les statistiques agrégées du compte sur une période : volumes, taux de livraison et de lecture, détail par jour, et solde courant.

Paramètres (optionnels)

  • periodtoday, 7days, 30days ou month (défaut : 30days).
  • from et to — dates au format YYYY-MM-DD (prioritaires sur period).
curl https://winochat.ma/api/v1/stats?period=7days \
  -H "Authorization: Bearer wch_VOTRE_CLE_API"
{
  "data": {
    "period": { "from": "2026-06-01", "to": "2026-06-07" },
    "totals": {
      "sent": 131,
      "delivered": 120,
      "read": 95,
      "failed": 6,
      "received": 33,
      "delivery_rate": 91.6,
      "read_rate": 72.5,
      "failure_rate": 4.6
    },
    "by_day": [
      { "date": "2026-06-07", "sent": 57, "delivered": 52, "read": 40, "failed": 1 }
    ],
    "balance": { "amount": 272.28, "currency": "MAD" }
  }
}

Connexion WhatsApp (QR)

Ces endpoints permettent d\'afficher le QR code de connexion WhatsApp directement dans votre application, et de surveiller l\'état de la ligne. La session WhatsApp reste gérée par WinoChat ; votre application ne fait qu\'afficher le QR et lire l\'état.

État de la ligne

GET/api/v1/wa/status

curl https://winochat.ma/api/v1/wa/status \
  -H "Authorization: Bearer wch_VOTRE_CLE_API"
{
  "data": {
    "connected": false,
    "phone": null,
    "qr_available": true,
    "state": "qr_pending"
  }
}

state vaut connected, qr_pending ou disconnected.

Demander un nouveau QR

POST/api/v1/wa/qr

Déclenche la génération d\'un nouveau QR. La génération prend environ 5 secondes (le temps que le service WhatsApp démarre la session).

curl -X POST https://winochat.ma/api/v1/wa/qr \
  -H "Authorization: Bearer wch_VOTRE_CLE_API"

Récupérer le QR

GET/api/v1/wa/qr

{
  "data": {
    "connected": false,
    "qr_available": true,
    "qr": "data:image/png;base64,iVBORw0K...",
    "expires_in": 52
  }
}

Le champ qr est une data-URL directement affichable dans une balise <img src="...">. Le QR expire après ~60s (expires_in en secondes).

Flux d\'intégration recommandé

  1. Appelez GET /wa/status. Si connected vaut true, la ligne est prête : aucune action.
  2. Sinon, appelez POST /wa/qr pour demander un QR.
  3. Attendez puis sondez GET /wa/qr toutes les 2 secondes. Le QR apparaît après ~5s (qr_available: true). N\'appelez pas une seule fois : sondez en boucle.
  4. Affichez la data-URL qr dans une balise <img>. L\'utilisateur la scanne depuis WhatsApp.
  5. Sondez GET /wa/status toutes les 3s. Dès que connected: true, la ligne est connectée.
Important : le QR n\'est pas instantané. Après POST /wa/qr, laissez ~5 secondes et sondez GET /wa/qr en boucle. Un seul appel immédiat renverra qr_available: false.
Sécurité : n\'exposez jamais votre clé API dans le JavaScript côté navigateur. Faites transiter ces appels par votre backend.

Codes d'erreur

Les erreurs renvoient un code HTTP approprié et un corps JSON :

{
  "error": {
    "code": "unauthorized",
    "message": "Clé API manquante ou invalide."
  }
}
HTTPcodeSignification
401unauthorizedClé API manquante, invalide ou révoquée.
400invalid_phoneNuméro de destinataire invalide.
400invalid_requestCorps JSON malformé ou paramètre requis manquant.
422wa_not_connectedLa ligne WhatsApp du compte n'est pas connectée.
422insufficient_fundsSolde insuffisant pour envoyer.
429rate_limitedTrop de requêtes : limite par minute ou quota dépassé.
500server_errorErreur interne. Réessayez ou contactez le support.

Limites de débit

Chaque clé a une limite de requêtes par minute (60 par défaut) et, le cas échéant, un quota quotidien. En cas de dépassement, l'API renvoie 429 rate_limited. Espacez vos envois ou contactez le support pour relever vos limites.

Webhooks

Configurez une URL de webhook (Tenant → Clés API → Webhook) pour recevoir les événements en temps réel par POST.

ÉvénementDéclenché quand…
message.sentLe message a été remis à WhatsApp.
message.deliveredLe message a été délivré au destinataire.
message.readLe message a été lu.
message.failedL'envoi a échoué.

Vérification de signature (HMAC)

Chaque requête inclut un en-tête X-Wino-Signature = HMAC-SHA256(secret, corps_brut).

$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WINO_SIGNATURE'] ?? '';
$expected  = hash_hmac('sha256', $payload, $secretWebhook);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Signature invalide');
}

Exemples de code

<?php
function winochat_send($to, $body) {
    $ch = curl_init('https://winochat.ma/api/v1/messages');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST           => true,
        CURLOPT_HTTPHEADER     => [
            'Authorization: Bearer wch_VOTRE_CLE_API',
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode([
            'to' => $to, 'body' => $body, 'type' => 'text',
        ]),
    ]);
    $res = curl_exec($ch);
    curl_close($ch);
    return json_decode($res, true);
}
async function winochatSend(to, body) {
  const res = await fetch('https://winochat.ma/api/v1/messages', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer wch_VOTRE_CLE_API',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ to, body, type: 'text' }),
  });
  return res.json();
}
# pip install requests
import requests

def winochat_send(to, body):
    r = requests.post(
        'https://winochat.ma/api/v1/messages',
        headers={
            'Authorization': 'Bearer wch_VOTRE_CLE_API',
            'Content-Type': 'application/json',
        },
        json={'to': to, 'body': body, 'type': 'text'},
        timeout=15,
    )
    return r.json()