POST /v1/actions/send-template-message

Envoie un message template WhatsApp approuvé par Meta à un contact. Fonctionne à tout moment — y compris en dehors de la fenêtre de service client de 24 h.

Envoie un message template approuvé par Meta. Les templates sont la seule manière d'envoyer un message à un contact en dehors de la fenêtre de service client de 24 h — et la seule manière d'engager une conversation avec quelqu'un à qui vous n'avez jamais écrit.

Le contact est upserté automatiquement par (tenant, phone) — pas besoin d'appeler create-contact au préalable.

POST /api/v1/actions/send-template-message

Corps de la requête

Champ Type Requis Notes
phone string oui Format international avec + (p. ex. +14155550123). Qyvo normalise les variations mineures.
template_id UUID oui L'id du template Qyvo (et non le nom Meta). Listez les templates pour découvrir les ids.
language string non p. ex. en, fr. Si omis (ou non approuvé), Qyvo se rabat sur n'importe quelle traduction approuvée.
variables object conditionnel Requis quand le corps du template contient des placeholders {{1}}, {{2}}. Les clés sont les noms des placeholders, les valeurs sont des chaînes.
curl -X POST https://www.qyvo.io/api/v1/actions/send-template-message \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+14155550123",
    "template_id": "01J0AB...",
    "language": "en",
    "variables": {
      "1": "Romain",
      "2": "ORD-1042"
    }
  }'
const res = await fetch('https://www.qyvo.io/api/v1/actions/send-template-message', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.QYVO_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    phone: '+14155550123',
    template_id: '01J0AB...',
    language: 'en',
    variables: { 1: 'Romain', 2: 'ORD-1042' },
  }),
});
Http::withToken(env('QYVO_TOKEN'))
    ->post('https://www.qyvo.io/api/v1/actions/send-template-message', [
        'phone' => '+14155550123',
        'template_id' => '01J0AB...',
        'language' => 'en',
        'variables' => ['1' => 'Romain', '2' => 'ORD-1042'],
    ])
    ->json();
import os, httpx
httpx.post(
    'https://www.qyvo.io/api/v1/actions/send-template-message',
    headers={'Authorization': f"Bearer {os.environ['QYVO_TOKEN']}"},
    json={
        'phone': '+14155550123',
        'template_id': '01J0AB...',
        'language': 'en',
        'variables': {'1': 'Romain', '2': 'ORD-1042'},
    },
).raise_for_status()

Réponse — 200 OK

{
  "id": "01J1Z...",
  "status": "sent",
  "whatsapp_message_id": "wamid.HBgL...",
  "contact_id": "01J1Y..."
}
Champ Notes
id Id de message Qyvo — apparaît dans l'Inbox ; reçoit les mises à jour de statut delivered/read ultérieures
status sent — Meta a accepté la requête. Les statuts asynchrones (delivered, read, failed) arrivent via webhooks.
whatsapp_message_id Le wamid.* de Meta — utile pour faire le rapprochement avec les logs Meta
contact_id Le contact (créé s'il n'existait pas)

Erreurs

Statut Corps Cause
404 Template not found Le template_id ne correspond à aucun template de votre tenant
422 Template requires variables that were not provided. Le corps a des {{N}} que vous n'avez pas passés. La réponse inclut expected_placeholders et missing.
422 Template has no approved translation to send. Le template est PENDING/REJECTED chez Meta. La réponse inclut available_languages.
422 No WhatsApp account configured Votre tenant n'a pas de WabaAccount — onboardez d'abord un numéro
422 Message d'erreur Meta remonté Voir Erreurs → codes Meta

Variables et placeholders

Le corps du template peut être :

Hi {{name}}, your order {{order}} is shipping today. Track it: {{tracking_url}}

Les placeholders sont extraits par Qyvo à partir du corps. Les clés variables doivent correspondre — les placeholders numériques (1, 2, …) et nommés sont tous deux pris en charge, selon la manière dont vous avez créé le template chez Meta.

Si vous passez trop peu de clés, vous obtiendrez :

{
  "error": "Template requires variables that were not provided.",
  "expected_placeholders": ["name", "order", "tracking_url"],
  "missing": ["tracking_url"]
}

Les valeurs doivent être des chaînes — convertissez les nombres/dates côté client.