Envoyer une image (logo, photo de produit, affiche) dans un message WhatsApp

Oui, avec un template dont l'en-tête est une IMAGE (JPEG ou PNG) : un exemple à la création, l'URL https de la vraie image à chaque envoi dans header_image_url. Un en-tête vidéo se crée mais ne s'envoie pas.

Envoyer une image (logo, photo de produit, affiche) dans un message WhatsApp

Astuce
Oui, avec un template dont l'en-tête est une IMAGE (JPEG ou PNG) : un exemple à la création, l'URL https de la vraie image à chaque envoi dans header_image_url. Un en-tête vidéo se crée mais ne s'envoie pas.

Scénario

Vous voulez qu'un message de notification s'ouvre sur une image : le logo de la boutique, la photo du produit commandé, l'affiche d'un événement.

Oui, via l'en-tête d'un template. Hors des 24 h, une image ne part pas seule : elle est l'en-tête d'un message à template. À la création vous joignez une image d'exemple ; à chaque envoi vous donnez l'adresse https de l'image à montrer.

Conversation

Vous    : POST /v1/messages  to=+237690000001  variables=["Awa", "CMD-1042"]
          header_image_url=https://files.example.com/produits/robe-wax.jpg
Awa     : [ photo de la robe ]
          « Bonjour Awa, votre commande CMD-1042 est confirmée. »

Code

  1. Créez le template. header_media_base64 est l'image d'exemple en base64 (header_image_base64 est accepté aussi), header_media_mime son type :

curl

curl -X POST "https://wa-api.geskap.com/v1/templates" \
  -H "Authorization: Bearer $GESKAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "commande_confirmee_photo",
  "language": "fr",
  "category": "UTILITY",
  "body_text": "Bonjour {{1}}, votre commande {{2}} est confirmée.",
  "example_values": ["Awa", "CMD-1042"],
  "header_media_base64": "<VOTRE_IMAGE_D_EXEMPLE_EN_BASE64>",
  "header_media_mime": "image/jpeg"
}'

Node.js

const res = await fetch("https://wa-api.geskap.com/v1/templates", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "commande_confirmee_photo",
    "language": "fr",
    "category": "UTILITY",
    "body_text": "Bonjour {{1}}, votre commande {{2}} est confirmée.",
    "example_values": ["Awa", "CMD-1042"],
    "header_media_base64": "<VOTRE_IMAGE_D_EXEMPLE_EN_BASE64>",
    "header_media_mime": "image/jpeg"
  }),
});
console.log(res.status, await res.json());

PHP

$ch = curl_init("https://wa-api.geskap.com/v1/templates");
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer " . getenv("GESKAP_API_KEY"),
    "Content-Type: application/json",
  ],
  CURLOPT_POSTFIELDS => json_encode([
    "name" => "commande_confirmee_photo",
    "language" => "fr",
    "category" => "UTILITY",
    "body_text" => "Bonjour {{1}}, votre commande {{2}} est confirmée.",
    "example_values" => ["Awa", "CMD-1042"],
    "header_media_base64" => "<VOTRE_IMAGE_D_EXEMPLE_EN_BASE64>",
    "header_media_mime" => "image/jpeg",
  ]),
]);
$res = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $res;

Python

import os, requests

res = requests.request(
    "POST",
    "https://wa-api.geskap.com/v1/templates",
    headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
    json={
        "name": "commande_confirmee_photo",
        "language": "fr",
        "category": "UTILITY",
        "body_text": "Bonjour {{1}}, votre commande {{2}} est confirmée.",
        "example_values": ["Awa", "CMD-1042"],
        "header_media_base64": "<VOTRE_IMAGE_D_EXEMPLE_EN_BASE64>",
        "header_media_mime": "image/jpeg",
    },
    timeout=15,
)
print(res.status_code, res.json())
  1. Une fois APPROVED, envoyez-le avec l'adresse de l'image de ce message :

curl

curl -X POST "https://wa-api.geskap.com/v1/messages" \
  -H "Authorization: Bearer $GESKAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "+237690000001",
  "template": {
    "name": "commande_confirmee_photo",
    "language": "fr",
    "variables": ["Awa", "CMD-1042"],
    "header_image_url": "https://files.example.com/produits/robe-wax.jpg"
  },
  "idempotency_key": "photo-CMD-1042"
}'

Node.js

const res = await fetch("https://wa-api.geskap.com/v1/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.GESKAP_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "to": "+237690000001",
    "template": {
      "name": "commande_confirmee_photo",
      "language": "fr",
      "variables": ["Awa", "CMD-1042"],
      "header_image_url": "https://files.example.com/produits/robe-wax.jpg"
    },
    "idempotency_key": "photo-CMD-1042"
  }),
});
console.log(res.status, await res.json());

PHP

$ch = curl_init("https://wa-api.geskap.com/v1/messages");
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer " . getenv("GESKAP_API_KEY"),
    "Content-Type: application/json",
  ],
  CURLOPT_POSTFIELDS => json_encode([
    "to" => "+237690000001",
    "template" => [
      "name" => "commande_confirmee_photo",
      "language" => "fr",
      "variables" => ["Awa", "CMD-1042"],
      "header_image_url" => "https://files.example.com/produits/robe-wax.jpg",
    ],
    "idempotency_key" => "photo-CMD-1042",
  ]),
]);
$res = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $res;

Python

import os, requests

res = requests.request(
    "POST",
    "https://wa-api.geskap.com/v1/messages",
    headers={"Authorization": f"Bearer {os.environ['GESKAP_API_KEY']}"},
    json={
        "to": "+237690000001",
        "template": {
            "name": "commande_confirmee_photo",
            "language": "fr",
            "variables": ["Awa", "CMD-1042"],
            "header_image_url": "https://files.example.com/produits/robe-wax.jpg",
        },
        "idempotency_key": "photo-CMD-1042",
    },
    timeout=15,
)
print(res.status_code, res.json())

Règles exactes

ÉlémentRègle
Types d'imageJPEG (image/jpeg) et PNG (image/png) seulement
Taille de l'exemple5 Mo au plus
Envoiheader_image_url : adresse https publique (pas de localhost, pas d'adresse privée)
Un seul en-têteheader_image_url ou header_document_url, jamais les deux (422)
Attention
Piège : le WebP est refusé en en-tête (WhatsApp ne l'accepte que pour les autocollants) : convertissez en PNG ou JPEG avant de créer le template.
Attention
Piège : l'image d'exemple n'est pas celle que le client voit. Elle sert à Meta pour valider le gabarit. L'image envoyée est celle de l'URL que vous donnez à chaque envoi, que Meta va chercher : elle doit être joignable depuis Internet.
Attention
Limite : un en-tête vidéo peut être créé (MP4 ou 3GPP, 16 Mo au plus), mais l'envoi par l'API n'a pas de paramètre vidéo : un template à en-tête vidéo part sans sa vidéo. Pour un fichier à joindre, utilisez un PDF en en-tête ; pour une image, ce modèle.
Attention
Piège : un template à image qui vend ou relance est de catégorie MARKETING : il répond 403 tant que l'envoi marketing n'est pas activé (voir Marketing et promo). Une confirmation de commande reste UTILITY.

Le template se crée une fois ; seule l'URL change d'un envoi à l'autre. Premier envoi, statuts et erreurs : Écrire à un client qui ne vous a jamais écrit. Si Meta refuse le template : Template refusé : les causes.

Preuve — vérifié dans le code de l'API : api_schemas.py, api_send.py.