Démarrer
Démarrage rapide
Créez un compte, générez une clé de bac à sable, déclarez un webhook et envoyez votre premier message en quelques minutes.
Mis à jour le 12 novembre 2026Voir en Markdown
Ce parcours utilise le bac à sable : rien n'est facturé et aucun vrai destinataire n'est contacté. Les exemples s'exécutent dans votre terminal ; chaque bloc existe en curl, Node.js, Python et PHP (votre choix de langage est mémorisé).
Définissez d'abord l'adresse de l'API :
export INBOX_API="https://VOTRE-HOTE/api/v1"Créez votre compte#
La création d'un compte crée aussi son premier membre (propriétaire) et ouvre une session.
curl -X POST "$INBOX_API/auth/signup" \
-H "Content-Type: application/json" \
-d '{
"accountName": "Acme Software",
"email": "dev@acme.com",
"password": "un-mot-de-passe-solide"
}'const res = await fetch(`${process.env.INBOX_API}/auth/signup`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"accountName": "Acme Software",
"email": "dev@acme.com",
"password": "un-mot-de-passe-solide"
}),
});
const data = await res.json();import os
import requests
res = requests.post(
f"{os.environ['INBOX_API']}/auth/signup",
json={
"accountName": "Acme Software",
"email": "dev@acme.com",
"password": "un-mot-de-passe-solide",
},
)
print(res.json())<?php
$ch = curl_init(getenv('INBOX_API') . '/auth/signup');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'accountName' => 'Acme Software',
'email' => 'dev@acme.com',
'password' => 'un-mot-de-passe-solide',
]),
]);
$data = json_decode(curl_exec($ch), true);{
"accountId": "bbfa1ecb-9483-4158-8e9a-4437e512b14b",
"memberId": "e8878e87-7817-4773-8346-fc26a2433aa6",
"sessionToken": "ses_91bb0d22558b4575a110844d944cca5d8b05e72328b",
"expiresAt": "2026-12-12T08:33:45.098Z"
}Le mot de passe doit contenir 10 caractères au minimum. Conservez le sessionToken : c'est la clé de la console, valable 30 jours.
export INBOX_SESSION="ses_…"Créez une application#
Une application a deux environnements : sandbox pour tester et production pour envoyer à de vrais destinataires. Ils sont strictement séparés.
curl -X POST "$INBOX_API/apps" \
-H "Authorization: Bearer $INBOX_SESSION" \
-H "Content-Type: application/json" \
-d '{
"name": "Mon CRM"
}'const res = await fetch(`${process.env.INBOX_API}/apps`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INBOX_SESSION}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "Mon CRM"
}),
});
const data = await res.json();import os
import requests
res = requests.post(
f"{os.environ['INBOX_API']}/apps",
headers={
"Authorization": f"Bearer {os.environ['INBOX_SESSION']}",
},
json={
"name": "Mon CRM",
},
)
print(res.json())<?php
$ch = curl_init(getenv('INBOX_API') . '/apps');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INBOX_SESSION'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Mon CRM',
]),
]);
$data = json_decode(curl_exec($ch), true);{
"id": "8b2717b6-be9e-42c7-8889-6e3c6ea4cbe3",
"name": "Mon CRM",
"createdAt": "2026-11-12T08:33:45.324Z",
"environments": [
{
"id": "7d3d2aa8-d312-48d7-894c-25b906dfa11a",
"kind": "sandbox"
},
{
"id": "badd0f25-05da-4716-8c28-f2fe1baba427",
"kind": "production"
}
]
}Générez une clé de sandbox#
Choisissez ses portées : une clé ne peut faire que ce que vous lui accordez.
curl -X POST "$INBOX_API/apps/APP_ID/keys" \
-H "Authorization: Bearer $INBOX_SESSION" \
-H "Content-Type: application/json" \
-d '{
"name": "Dev local",
"environment": "sandbox",
"scopes": [
"messages:send",
"messages:read",
"connections:manage",
"connections:read",
"templates:manage",
"webhooks:manage",
"usage:read"
]
}'const res = await fetch(`${process.env.INBOX_API}/apps/APP_ID/keys`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INBOX_SESSION}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "Dev local",
"environment": "sandbox",
"scopes": [
"messages:send",
"messages:read",
"connections:manage",
"connections:read",
"templates:manage",
"webhooks:manage",
"usage:read"
]
}),
});
const data = await res.json();import os
import requests
res = requests.post(
f"{os.environ['INBOX_API']}/apps/APP_ID/keys",
headers={
"Authorization": f"Bearer {os.environ['INBOX_SESSION']}",
},
json={
"name": "Dev local",
"environment": "sandbox",
"scopes": [
"messages:send",
"messages:read",
"connections:manage",
"connections:read",
"templates:manage",
"webhooks:manage",
"usage:read",
],
},
)
print(res.json())<?php
$ch = curl_init(getenv('INBOX_API') . '/apps/APP_ID/keys');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INBOX_SESSION'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Dev local',
'environment' => 'sandbox',
'scopes' => [
'messages:send',
'messages:read',
'connections:manage',
'connections:read',
'templates:manage',
'webhooks:manage',
'usage:read',
],
]),
]);
$data = json_decode(curl_exec($ch), true);{
"id": "5ef37bc9-8aac-43ef-81b1-6bb3bdb66e78",
"name": "Dev local",
"prefix": "pk_test_bwcA3X-A",
"environment": "sandbox",
"scopes": [
"messages:send",
"messages:read",
"connections:manage",
"connections:read",
"templates:manage",
"webhooks:manage",
"usage:read"
],
"lastUsedAt": null,
"revokedAt": null,
"createdAt": "2026-11-12T08:33:45.382Z",
"secret": "pk_test_26f602c48c47ef280792fd3a506473688df70b80118"
}export INBOX_KEY="pk_test_…"Déclarez l'entreprise de votre client#
Une entreprise connectée représente votre client, propriétaire d'un compte WhatsApp Business. externalRef est votre propre identifiant de ce client.
curl -X POST "$INBOX_API/connected-businesses" \
-H "Authorization: Bearer $INBOX_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Cabinet Dentaire Zokem",
"externalRef": "client-42"
}'const res = await fetch(`${process.env.INBOX_API}/connected-businesses`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INBOX_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "Cabinet Dentaire Zokem",
"externalRef": "client-42"
}),
});
const data = await res.json();import os
import requests
res = requests.post(
f"{os.environ['INBOX_API']}/connected-businesses",
headers={
"Authorization": f"Bearer {os.environ['INBOX_KEY']}",
},
json={
"name": "Cabinet Dentaire Zokem",
"externalRef": "client-42",
},
)
print(res.json())<?php
$ch = curl_init(getenv('INBOX_API') . '/connected-businesses');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INBOX_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Cabinet Dentaire Zokem',
'externalRef' => 'client-42',
]),
]);
$data = json_decode(curl_exec($ch), true);{
"id": "39e2803f-79e7-4e99-8da0-1c15991f5985",
"name": "Cabinet Dentaire Zokem",
"externalRef": "client-42",
"createdAt": "2026-11-12T08:33:45.469Z"
}Connectez son compte WhatsApp#
Votre client termine l'inscription intégrée de Meta dans le navigateur ; vous recevez un code, un wabaId et un phoneNumberId que vous transmettez à l'API. Voir Connecter un compte WhatsApp.
curl -X POST "$INBOX_API/connected-businesses/BUSINESS_ID/waba-connections" \
-H "Authorization: Bearer $INBOX_KEY" \
-H "Content-Type: application/json" \
-d '{
"code": "AQBx7…",
"wabaId": "102290129340398",
"phoneNumberId": "106540352242922",
"mode": "cloud_api"
}'const res = await fetch(`${process.env.INBOX_API}/connected-businesses/BUSINESS_ID/waba-connections`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INBOX_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"code": "AQBx7…",
"wabaId": "102290129340398",
"phoneNumberId": "106540352242922",
"mode": "cloud_api"
}),
});
const data = await res.json();import os
import requests
res = requests.post(
f"{os.environ['INBOX_API']}/connected-businesses/BUSINESS_ID/waba-connections",
headers={
"Authorization": f"Bearer {os.environ['INBOX_KEY']}",
},
json={
"code": "AQBx7…",
"wabaId": "102290129340398",
"phoneNumberId": "106540352242922",
"mode": "cloud_api",
},
)
print(res.json())<?php
$ch = curl_init(getenv('INBOX_API') . '/connected-businesses/BUSINESS_ID/waba-connections');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INBOX_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'code' => 'AQBx7…',
'wabaId' => '102290129340398',
'phoneNumberId' => '106540352242922',
'mode' => 'cloud_api',
]),
]);
$data = json_decode(curl_exec($ch), true);{
"id": "b76a1f98-53d6-4078-8d28-6406482daabb",
"wabaId": "102290129340398",
"status": "active",
"mode": "cloud_api",
"phoneNumber": {
"id": "4d8e654e-d744-4bf3-8211-9ceffcccfe87",
"phoneNumberId": "106540352242922",
"displayNumber": "+237 6 52242922",
"verifiedName": "Cabinet Test",
"qualityRating": "GREEN"
}
}Notez l'id du numéro (phoneNumber.id) : c'est lui qui désigne le numéro d'envoi.
Recevez les événements#
Déclarez la destination de vos webhooks. Le secret de signature n'est affiché qu'une fois.
curl -X POST "$INBOX_API/webhook-endpoints" \
-H "Authorization: Bearer $INBOX_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.exemple.com/webhooks/inbox",
"events": [
"message.received",
"message.delivered",
"message.failed"
]
}'const res = await fetch(`${process.env.INBOX_API}/webhook-endpoints`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INBOX_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"url": "https://api.exemple.com/webhooks/inbox",
"events": [
"message.received",
"message.delivered",
"message.failed"
]
}),
});
const data = await res.json();import os
import requests
res = requests.post(
f"{os.environ['INBOX_API']}/webhook-endpoints",
headers={
"Authorization": f"Bearer {os.environ['INBOX_KEY']}",
},
json={
"url": "https://api.exemple.com/webhooks/inbox",
"events": [
"message.received",
"message.delivered",
"message.failed",
],
},
)
print(res.json())<?php
$ch = curl_init(getenv('INBOX_API') . '/webhook-endpoints');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INBOX_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'url' => 'https://api.exemple.com/webhooks/inbox',
'events' => [
'message.received',
'message.delivered',
'message.failed',
],
]),
]);
$data = json_decode(curl_exec($ch), true);{
"id": "bc06ae32-7564-46d5-89fb-a9869019aa8e",
"url": "https://api.exemple.com/webhooks/inbox",
"events": [
"message.received",
"message.delivered",
"message.failed"
],
"status": "active",
"consecutiveFailures": 0,
"disabledReason": null,
"createdAt": "2026-11-12T08:33:45.704Z",
"secret": "whsec_b4ac869893324714f88bfd25026b3e2e2891bb8c087"
}Vérifiez que votre serveur répond bien, avec un événement de test signé :
curl -X POST "$INBOX_API/webhook-endpoints/ID/test" \
-H "Authorization: Bearer $INBOX_KEY"const res = await fetch(`${process.env.INBOX_API}/webhook-endpoints/ID/test`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INBOX_KEY}`,
},
});
const data = await res.json();import os
import requests
res = requests.post(
f"{os.environ['INBOX_API']}/webhook-endpoints/ID/test",
headers={
"Authorization": f"Bearer {os.environ['INBOX_KEY']}",
},
)
print(res.json())<?php
$ch = curl_init(getenv('INBOX_API') . '/webhook-endpoints/ID/test');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INBOX_KEY'),
],
]);
$data = json_decode(curl_exec($ch), true);{
"ok": true,
"statusCode": 200,
"durationMs": 3,
"error": null
}Envoyez votre premier message#
curl -X POST "$INBOX_API/messages" \
-H "Authorization: Bearer $INBOX_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: rdv-2026-11-14-client-42" \
-d '{
"phoneNumberId": "4d8e654e-d744-4bf3-8211-9ceffcccfe87",
"to": "+237600000000",
"type": "template",
"template": {
"name": "rappel_rdv",
"language": "fr",
"components": [
{
"type": "body",
"parameters": [
{
"type": "text",
"text": "Awa"
},
{
"type": "text",
"text": "14 novembre à 10 h"
}
]
}
]
}
}'const res = await fetch(`${process.env.INBOX_API}/messages`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INBOX_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "rdv-2026-11-14-client-42",
},
body: JSON.stringify({
"phoneNumberId": "4d8e654e-d744-4bf3-8211-9ceffcccfe87",
"to": "+237600000000",
"type": "template",
"template": {
"name": "rappel_rdv",
"language": "fr",
"components": [
{
"type": "body",
"parameters": [
{
"type": "text",
"text": "Awa"
},
{
"type": "text",
"text": "14 novembre à 10 h"
}
]
}
]
}
}),
});
const data = await res.json();import os
import requests
res = requests.post(
f"{os.environ['INBOX_API']}/messages",
headers={
"Authorization": f"Bearer {os.environ['INBOX_KEY']}",
"Idempotency-Key": "rdv-2026-11-14-client-42",
},
json={
"phoneNumberId": "4d8e654e-d744-4bf3-8211-9ceffcccfe87",
"to": "+237600000000",
"type": "template",
"template": {
"name": "rappel_rdv",
"language": "fr",
"components": [
{
"type": "body",
"parameters": [
{
"type": "text",
"text": "Awa",
},
{
"type": "text",
"text": "14 novembre à 10 h",
},
],
},
],
},
},
)
print(res.json())<?php
$ch = curl_init(getenv('INBOX_API') . '/messages');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INBOX_KEY'),
'Content-Type: application/json',
'Idempotency-Key: rdv-2026-11-14-client-42',
],
CURLOPT_POSTFIELDS => json_encode([
'phoneNumberId' => '4d8e654e-d744-4bf3-8211-9ceffcccfe87',
'to' => '+237600000000',
'type' => 'template',
'template' => [
'name' => 'rappel_rdv',
'language' => 'fr',
'components' => [
[
'type' => 'body',
'parameters' => [
[
'type' => 'text',
'text' => 'Awa',
],
[
'type' => 'text',
'text' => '14 novembre à 10 h',
],
],
],
],
],
]),
]);
$data = json_decode(curl_exec($ch), true);{
"id": "d5ad1e3e-6ab9-4f7f-8e4e-b17104a7bd00",
"direction": "outbound",
"status": "queued",
"type": "template",
"phoneNumberId": "4d8e654e-d744-4bf3-8211-9ceffcccfe87",
"to": "237600000000",
"waMessageId": null,
"content": {
"type": "template",
"template": {
"name": "rappel_rdv",
"language": "fr",
"components": [
{
"type": "body",
"parameters": [
{
"type": "text",
"text": "Awa"
},
{
"type": "text",
"text": "14 novembre à 10 h"
}
]
}
]
}
},
"error": null,
"createdAt": "2026-11-12T08:33:45.855Z",
"sentAt": null,
"deliveredAt": null,
"readAt": null
}La réponse est immédiate (202, statut queued) : l'envoi réel est asynchrone. Suivez le statut avec GET /messages/{id} ou, mieux, avec vos webhooks.
Simulez une réponse du client#
Sans téléphone, faites « arriver » un message : votre webhook message.received se déclenche exactement comme en production.
curl -X POST "$INBOX_API/sandbox/simulate/inbound-message" \
-H "Authorization: Bearer $INBOX_KEY" \
-H "Content-Type: application/json" \
-d '{
"phoneNumberId": "4d8e654e-d744-4bf3-8211-9ceffcccfe87",
"from": "+237611111111",
"text": "Bonjour, je voudrais déplacer mon rendez-vous"
}'const res = await fetch(`${process.env.INBOX_API}/sandbox/simulate/inbound-message`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.INBOX_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"phoneNumberId": "4d8e654e-d744-4bf3-8211-9ceffcccfe87",
"from": "+237611111111",
"text": "Bonjour, je voudrais déplacer mon rendez-vous"
}),
});
const data = await res.json();import os
import requests
res = requests.post(
f"{os.environ['INBOX_API']}/sandbox/simulate/inbound-message",
headers={
"Authorization": f"Bearer {os.environ['INBOX_KEY']}",
},
json={
"phoneNumberId": "4d8e654e-d744-4bf3-8211-9ceffcccfe87",
"from": "+237611111111",
"text": "Bonjour, je voudrais déplacer mon rendez-vous",
},
)
print(res.json())<?php
$ch = curl_init(getenv('INBOX_API') . '/sandbox/simulate/inbound-message');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('INBOX_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'phoneNumberId' => '4d8e654e-d744-4bf3-8211-9ceffcccfe87',
'from' => '+237611111111',
'text' => 'Bonjour, je voudrais déplacer mon rendez-vous',
]),
]);
$data = json_decode(curl_exec($ch), true);{
"messageId": "3f3baf5a-f93e-42e8-8263-ce62dc4aadd6",
"from": "237611111111",
"status": "received",
"simulated": true
}Et ensuite#
- Authentification et clés : portées, rotation, bonnes pratiques.
- Webhooks : vérifier la signature, dédoublonner, rejouer.
- Fiabilité : idempotence et reprises.
- Passer en production : plan, quotas, coûts.