Démarrage rapide #
Intégrez l'envoi de SMS en quelques minutes avec notre API REST simple et puissante.
Créer un compte
Inscrivez-vous gratuitement sur Callisto
Obtenir une clé API
Générez votre clé dans le tableau de bord
Envoyer un SMS ou WhatsApp
Faites votre premier appel API
Authentification #
L'API Callisto utilise l'authentification HTTP Basic. Chaque requête doit inclure un en-tête Authorization contenant vos identifiants encodés en base64.
Vos identifiants
Chaque clé API génère deux valeurs : access_key (identifiant public) et access_secret (à garder confidentiel). Récupérez-les depuis le tableau de bord à /api-keys.
Format de l'en-tête
Concaténez vos identifiants avec un deux-points puis encodez en base64 :
Authorization: Basic <base64(access_key:access_secret)>
Exemple avec cURL
Le drapeau -u de cURL encode automatiquement vos identifiants :
curl -u 'ak_xxx:sk_xxx' https://api.callistosignal.com/v1/sms/balance
URL de base #
https://api.callistosignal.com/v1
Envoyer un SMS #
POST /v1/sms/sendParamètres
| Paramètre | Type | Requis | Description |
|---|---|---|---|
to |
string | array | Oui | Numéro(s) de téléphone du/des destinataire(s) (format international) |
message |
string | Oui | Contenu du message (max 1600 caractères) |
sender_id |
string | Non | Identifiant de l'expéditeur (doit être approuvé) |
scheduled_at |
datetime | Non | Date et heure d'envoi programmé (ISO 8601) |
Exemple de requête
// Envoyer un SMS
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/sms/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
to: '+22507XXXXXXXX',
message: 'Bonjour',
sender: 'MyApp'
})
});
const data = await res.json();
// Envoyer un SMS via cURL
$ch = curl_init('https://api.callistosignal.com/v1/sms/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+22507XXXXXXXX',
'message' => 'Bonjour',
'sender' => 'MyApp',
]),
]);
$response = curl_exec($ch);
curl_close($ch);
# Envoyer un SMS
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
-X POST https://api.callistosignal.com/v1/sms/send \
-H 'Content-Type: application/json' \
-d '{
"to": "+22507XXXXXXXX",
"message": "Bonjour",
"sender": "MyApp"
}'
Réponse
{
"success": true,
"data": {
"id": "msg_abc123xyz",
"to": ["+22507XXXXXXXX"],
"status": "queued",
"credits_used": 1,
"created_at": "2026-02-01T10:30:00Z"
}
}
Envoi en masse #
POST /v1/sms/sendEnvoyez le même message à plusieurs destinataires en une seule requête.
Exemple de requête
// Envoyer un SMS en masse
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/sms/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
to: ['+22507XXXXXXXX', '+22508XXXXXXXX'],
message: 'Bonjour à tous',
sender: 'MyApp'
})
});
// Envoyer un SMS en masse
$ch = curl_init('https://api.callistosignal.com/v1/sms/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'to' => ['+22507XXXXXXXX', '+22508XXXXXXXX'],
'message' => 'Bonjour à tous',
'sender' => 'MyApp',
]),
]);
$response = curl_exec($ch);
# Envoyer un SMS en masse
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
-X POST https://api.callistosignal.com/v1/sms/send \
-H 'Content-Type: application/json' \
-d '{
"to": ["+22507XXXXXXXX", "+22508XXXXXXXX"],
"message": "Bonjour à tous",
"sender": "MyApp"
}'
OTP — Envoyer un code #
POST /v1/otp/send/otp/send
Envoyez un code de vérification unique (OTP) à un destinataire. Le code est généré automatiquement et inséré dans votre message via la variable {code}.
Paramètres
| Paramètre | Type | Requis | Description |
|---|---|---|---|
to |
string | Oui | Numéro de téléphone du destinataire (format international) |
message |
string | Oui | Message contenant {code} (5-500 caractères) |
sender |
string | Non | Identifiant de l'expéditeur (doit être approuvé). Ignoré pour le canal WhatsApp. |
expired_in |
integer | Oui | Durée de validité en secondes (60 - 86400) |
digit_size |
integer | Non | Nombre de caractères du code (4-16, défaut: 6) |
type |
string | Non | Type de code: digit, alpha, alphanumeric (défaut: digit) |
provider |
string | Non | Canal de livraison: sms (défaut) ou whatsapp |
instanceCode |
string | Conditionnel | Code de l'instance WhatsApp à utiliser. Requis lorsque provider = whatsapp. |
Exemple de requête
// Envoyer un code OTP
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/otp/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
to: '+22507XXXXXXXX',
message: 'Votre code de vérification est {code}',
sender: 'MyApp',
digit_size: 6,
expired_in: 300,
type: 'digit',
provider: 'sms'
})
});
const { id, recipient, expires_at } = await res.json();
// Envoyer un code OTP
$ch = curl_init('https://api.callistosignal.com/v1/otp/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+22507XXXXXXXX',
'message' => 'Votre code de vérification est {code}',
'sender' => 'MyApp',
'digit_size' => 6,
'expired_in' => 300,
'type' => 'digit',
'provider' => 'sms',
]),
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
-X POST https://api.callistosignal.com/v1/otp/send \
-H 'Content-Type: application/json' \
-d '{
"to": "+22507XXXXXXXX",
"message": "Votre code de vérification est {code}",
"sender": "MyApp",
"digit_size": 6,
"expired_in": 300,
"type": "digit",
"provider": "sms"
}'
Réponse
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"provider": "sms",
"recipient": "+22507XXXXXXXX",
"expires_at": "2026-04-07T10:35:00Z",
"expires_in": 300
}
Variante : livraison via WhatsApp
Pour envoyer le code via une instance WhatsApp connectée, ajoutez provider: "whatsapp" et instanceCode. Le champ sender est ignoré dans ce mode.
{
"to": "+22507XXXXXXXX",
"message": "Votre code Callisto est {code}",
"expired_in": 300,
"digit_size": 6,
"type": "digit",
"provider": "whatsapp",
"instanceCode": "{instanceCode}"
}
Réponse identique, avec "provider": "whatsapp". Renvoie 400 si instanceCode est manquant ou si l'instance n'est pas connectée.
Note : Conservez l'id retourné pour vérifier le code ultérieurement.
OTP — Vérifier un code #
POST /v1/otp/verify/otp/verify
Vérifiez le code OTP saisi par l'utilisateur.
Paramètres
| Paramètre | Type | Requis | Description |
|---|---|---|---|
otp_id |
string | Oui | ID de l'OTP retourné lors de l'envoi (UUID) |
code |
string | Oui | Code saisi par l'utilisateur (4-16 caractères) |
Exemple de requête
// Vérifier un code OTP
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/otp/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
otp_id: 'otp_xxxxxx',
code: '123456'
})
});
// Vérifier un code OTP
$ch = curl_init('https://api.callistosignal.com/v1/otp/verify');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'otp_id' => 'otp_xxxxxx',
'code' => '123456',
]),
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
-X POST https://api.callistosignal.com/v1/otp/verify \
-H 'Content-Type: application/json' \
-d '{
"otp_id": "otp_xxxxxx",
"code": "123456"
}'
Réponse (succès)
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "verified",
"verified": true,
"verified_at": "2026-04-07T10:32:15Z"
}
Réponse (échec)
{
"message": "Invalid OTP code"
}
Codes d'erreur OTP
| Code | Description |
|---|---|
400 |
Code OTP invalide |
404 |
OTP non trouvé |
410 |
OTP expiré |
429 |
Trop de tentatives de vérification |
OTP — Statut #
GET /v1/otps/{id}/otps/{{otp_id}}
Récupérez le statut actuel d'un OTP.
Exemple de requête
// Consulter le statut d'un code OTP
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/otps/otp_xxxxxx', {
headers: { 'Authorization': 'Basic ' + credentials }
});
// Consulter le statut d'un code OTP
$ch = curl_init('https://api.callistosignal.com/v1/otps/otp_xxxxxx');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
https://api.callistosignal.com/v1/otps/otp_xxxxxx
Réponse
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"recipient": "+22507XXXXXXXX",
"status": "pending",
"created_at": "2026-04-07T10:30:00Z",
"expires_at": "2026-04-07T10:35:00Z",
"verified_at": null
}
Statuts possibles
| Statut | Description |
|---|---|
| pending | En attente de vérification |
| verified | Code vérifié avec succès |
| expired | Code expiré |
OTP — Liste #
GET /v1/otps/otps
Récupérez la liste des OTP avec pagination.
Paramètres de requête
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
page |
integer | 1 | Numéro de page |
limit |
integer | 20 | Nombre d'éléments par page |
started_at |
date | -30 jours | Date de début (YYYY-MM-DD) |
ended_at |
date | aujourd'hui | Date de fin (YYYY-MM-DD) |
Exemple de requête
// Lister les codes OTP envoyés
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/otps?limit=50', {
headers: { 'Authorization': 'Basic ' + credentials }
});
// Lister les codes OTP envoyés
$ch = curl_init('https://api.callistosignal.com/v1/otps?limit=50');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
'https://api.callistosignal.com/v1/otps?limit=50'
Réponse
{
"items": [
{
"id": "3b5d654b-d603-44b6-8f9e-0f24b38eafd0",
"client_id": "9d8e0eab-6c65-4794-ae22-637445a421bf",
"client_api_id": "c11e9a92-27eb-430f-949f-40dea00d521d",
"message_id": "ea01e0ba-02d2-471a-8e23-340b7d570b3e",
"recipient": "+22507XXXXXXXX",
"status": "expired",
"expires_at": "2026-04-07 19:05:12",
"verified_at": null,
"attempts": 0,
"created_at": "2026-04-07 18:06:52",
"updated_at": "2026-04-07 18:06:52"
},
{
"id": "d5f29dfc-03b5-41da-b371-2d7998896c72",
"client_id": "9d8e0eab-6c65-4794-ae22-637445a421bf",
"client_api_id": "c11e9a92-27eb-430f-949f-40dea00d521d",
"message_id": "ac118655-fe08-4eba-afb1-e4a7a5399a95",
"recipient": "+22508XXXXXXXX",
"status": "verified",
"expires_at": "2026-04-07 18:55:37",
"verified_at": "2026-04-07 18:52:15",
"attempts": 1,
"created_at": "2026-04-07 17:57:17",
"updated_at": "2026-04-07 18:52:15"
}
],
"total": 25,
"per_page": 20,
"current_page": 1,
"next": 2,
"previous": 0,
"total_pages": 2
}
Connecter une instance #
WhatsApp Business nécessite de pairer une fois un numéro de téléphone via QR code dans le tableau de bord. L'API REST ne prend pas en charge le pairing — elle commence à partir de l'envoi de messages et de la consultation des statuts.
Étapes
- Connectez-vous à votre tableau de bord.
- Allez dans WhatsApp → Instances → Nouvelle instance.
- Nommez l'instance (par exemple "Production" ou "Support").
- Scannez le QR code affiché avec WhatsApp Business sur le téléphone qui hébergera l'instance.
- Une fois
status: connected, vous pouvez envoyer des messages via l'API.
Instances #
Consulter la liste de vos instances WhatsApp pairées et leur statut.
Lister les instances
GET /v1/whatsapp/instances// Lister les instances WhatsApp
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/whatsapp/instances', {
headers: { 'Authorization': 'Basic ' + credentials }
});
const instances = await res.json();
// Lister les instances WhatsApp
$ch = curl_init('https://api.callistosignal.com/v1/whatsapp/instances');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
https://api.callistosignal.com/v1/whatsapp/instances
Réponse (200)
[
{
"id": "{instanceCode}",
"name": "Production",
"phone_number": "+22507XXXXXXXX",
"phone_name": "Callisto Demo",
"status": "connected",
"billing_status": "active",
"trial_days_remaining": 0,
"monthly_fee": 5000,
"created_at": "2026-04-12T10:34:00Z"
}
]
Détails d'une instance
GET /v1/whatsapp/{instanceCode}
Paramètre de chemin : instanceCode — UUID de l'instance.
// Consulter une instance WhatsApp
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/whatsapp/{instanceCode}', {
headers: { 'Authorization': 'Basic ' + credentials }
});
const instance = await res.json();
// Consulter une instance WhatsApp
$ch = curl_init('https://api.callistosignal.com/v1/whatsapp/{instanceCode}');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
https://api.callistosignal.com/v1/whatsapp/{instanceCode}
Réponse (200)
{
"id": "{instanceCode}",
"name": "Production",
"phone_number": "+22507XXXXXXXX",
"phone_name": "Callisto Demo",
"status": "connected",
"billing_status": "active",
"trial_days_remaining": 0,
"monthly_fee": 5000,
"created_at": "2026-04-12T10:34:00Z"
}
Envoyer un message #
Une fois votre instance pairée et connected, envoyez des messages texte ou média via l'API.
Message texte
POST /v1/whatsapp/{instanceCode}/send/textParamètres du corps
| Paramètre | Type | Requis | Description |
|---|---|---|---|
| to | string | Oui | Numéro destinataire au format E.164 (ex. +22507XXXXXXXX). |
| message | string | Oui | Contenu du message texte. |
// Envoyer un message texte WhatsApp
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/text', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
to: '+22507XXXXXXXX',
message: 'Bonjour Aïcha'
})
});
// Envoyer un message texte WhatsApp
$ch = curl_init('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/text');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+22507XXXXXXXX',
'message' => 'Bonjour Aïcha',
]),
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
-X POST https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/text \
-H 'Content-Type: application/json' \
-d '{"to":"+22507XXXXXXXX","message":"Bonjour Aïcha"}'
Réponse (200)
{
"id": "wmsg_xxxxxx",
"instance_id": "{instanceCode}",
"to": "+22507XXXXXXXX",
"status": "queued"
}
Message média
POST /v1/whatsapp/{instanceCode}/send/mediaParamètres du corps
| Paramètre | Type | Requis | Description |
|---|---|---|---|
| to | string | Oui | Numéro destinataire (E.164). |
| type | string | Oui | image |
| media_url | string | Oui | URL publique du média (http:// ou https://). |
| caption | string | Non | Légende affichée avec le média (max 1024 caractères). |
| filename | string | Non | Nom du fichier (utile pour document, max 255 caractères). |
// Envoyer un média WhatsApp
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/media', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
to: '+22507XXXXXXXX',
type: 'image',
media_url: 'https://example.com/photo.jpg',
caption: 'Notre nouveau produit'
})
});
// Envoyer un média WhatsApp
$ch = curl_init('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/media');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+22507XXXXXXXX',
'type' => 'image',
'media_url' => 'https://example.com/photo.jpg',
'caption' => 'Notre nouveau produit',
]),
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
-X POST https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/media \
-H 'Content-Type: application/json' \
-d '{"to":"+22507XXXXXXXX","type":"image","media_url":"https://example.com/photo.jpg","caption":"Notre nouveau produit"}'
Réponse (200)
{
"id": "wmsg_xxxxxx",
"instance_id": "{instanceCode}",
"to": "+22507XXXXXXXX",
"status": "queued"
}
Message boutons
POST /v1/whatsapp/{instanceCode}/send/buttonsParamètres du corps
| Paramètre | Type | Requis | Description |
|---|---|---|---|
| to | string | Oui | Numéro destinataire (E.164). |
| body | string | Oui | Texte principal du message (max 1024 caractères). |
| buttons | array | Oui | 1 à 3 boutons {id, title}. title ≤ 20 caractères, id ≤ 256 caractères. |
| header | string | Non | En-tête optionnel (≤ 60 caractères). |
| footer | string | Non | Pied de message optionnel (≤ 60 caractères). |
| scheduled_at | datetime | Non | Différer l'envoi (YYYY-MM-DD HH:MM:SS). |
// Envoyer un message à boutons WhatsApp
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/buttons', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
to: '+22507XXXXXXXX',
body: 'Confirmez-vous votre commande ?',
header: 'Commande #1234',
footer: 'Répondez à tout moment.',
buttons: [
{ id: 'yes', title: 'Oui' },
{ id: 'no', title: 'Non' },
{ id: 'later', title: 'Plus tard' }
]
})
});
// Envoyer un message à boutons WhatsApp
$ch = curl_init('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/buttons');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+22507XXXXXXXX',
'body' => 'Confirmez-vous votre commande ?',
'header' => 'Commande #1234',
'footer' => 'Répondez à tout moment.',
'buttons' => [
['id' => 'yes', 'title' => 'Oui'],
['id' => 'no', 'title' => 'Non'],
['id' => 'later', 'title' => 'Plus tard'],
],
]),
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
-X POST https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/buttons \
-H 'Content-Type: application/json' \
-d '{"to":"+22507XXXXXXXX","body":"Confirmez-vous ?","buttons":[{"id":"yes","title":"Oui"},{"id":"no","title":"Non"}]}'
Réponse (200)
{
"id": "wmsg_xxxxxx",
"instance_id": "{instanceCode}",
"recipient": "+22507XXXXXXXX",
"message_type": "buttons",
"status": "queued",
"scheduled": false
}
Message localisation
POST /v1/whatsapp/{instanceCode}/send/locationParamètres du corps
| Paramètre | Type | Requis | Description |
|---|---|---|---|
| to | string | Oui | Numéro destinataire (E.164). |
| latitude | number | Oui | Latitude entre -90 et 90. |
| longitude | number | Oui | Longitude entre -180 et 180. |
| name | string | Non | Nom du lieu (≤ 255 caractères). |
| address | string | Non | Adresse postale (≤ 1024 caractères). |
| scheduled_at | datetime | Non | Différer l'envoi. |
// Envoyer une localisation WhatsApp
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/location', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
to: '+22507XXXXXXXX',
latitude: 5.3599517,
longitude: -4.0082563,
name: 'Plateau, Abidjan',
address: 'Boulevard de la République, Abidjan'
})
});
// Envoyer une localisation WhatsApp
$ch = curl_init('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/location');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+22507XXXXXXXX',
'latitude' => 5.3599517,
'longitude' => -4.0082563,
'name' => 'Plateau, Abidjan',
'address' => 'Boulevard de la République, Abidjan',
]),
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
-X POST https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/location \
-H 'Content-Type: application/json' \
-d '{"to":"+22507XXXXXXXX","latitude":5.3599517,"longitude":-4.0082563,"name":"Plateau, Abidjan"}'
Réponse (200)
{
"id": "wmsg_xxxxxx",
"instance_id": "{instanceCode}",
"recipient": "+22507XXXXXXXX",
"message_type": "location",
"status": "queued",
"scheduled": false
}
Message liste
POST /v1/whatsapp/{instanceCode}/send/listParamètres du corps
| Paramètre | Type | Requis | Description |
|---|---|---|---|
| to | string | Oui | Numéro destinataire (E.164). |
| body | string | Oui | Texte principal (max 1024 caractères). |
| button_text | string | Oui | Libellé du bouton qui ouvre la liste (≤ 20 caractères). |
| sections | array | Oui | 1 à 10 sections {title, rows}. Total des rows ≤ 10. Chaque ligne {id, title, description?} avec title ≤ 24 et description ≤ 72. |
| header | string | Non | En-tête optionnel (≤ 60 caractères). |
| footer | string | Non | Pied de message optionnel (≤ 60 caractères). |
| scheduled_at | datetime | Non | Différer l'envoi. |
// Envoyer un menu liste WhatsApp
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/list', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
to: '+22507XXXXXXXX',
body: 'Sélectionnez une option dans le menu.',
button_text: 'Voir le menu',
header: 'Notre catalogue',
sections: [
{
title: 'Plats',
rows: [
{ id: 'plat-1', title: 'Attiéké poisson', description: 'Avec sauce piment' },
{ id: 'plat-2', title: 'Garba' }
]
},
{
title: 'Boissons',
rows: [
{ id: 'bsn-1', title: 'Bissap' },
{ id: 'bsn-2', title: 'Gnamakoudji' }
]
}
]
})
});
// Envoyer un menu liste WhatsApp
$ch = curl_init('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/list');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+22507XXXXXXXX',
'body' => 'Sélectionnez une option dans le menu.',
'button_text' => 'Voir le menu',
'header' => 'Notre catalogue',
'sections' => [
[
'title' => 'Plats',
'rows' => [
['id' => 'plat-1', 'title' => 'Attiéké poisson', 'description' => 'Avec sauce piment'],
['id' => 'plat-2', 'title' => 'Garba'],
],
],
[
'title' => 'Boissons',
'rows' => [
['id' => 'bsn-1', 'title' => 'Bissap'],
['id' => 'bsn-2', 'title' => 'Gnamakoudji'],
],
],
],
]),
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
-X POST https://api.callistosignal.com/v1/whatsapp/{instanceCode}/send/list \
-H 'Content-Type: application/json' \
-d '{"to":"+22507XXXXXXXX","body":"Choisir une option","button_text":"Menu","sections":[{"title":"Plats","rows":[{"id":"a","title":"Garba"}]}]}'
Réponse (200)
{
"id": "wmsg_xxxxxx",
"instance_id": "{instanceCode}",
"recipient": "+22507XXXXXXXX",
"message_type": "list",
"status": "queued",
"scheduled": false
}
Messages WhatsApp #
Lister les messages envoyés depuis une instance, ou consulter le statut d'un message individuel.
Lister les messages d'une instance
GET /v1/whatsapp/{instanceCode}/messagesParamètres de requête
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
| limit | int | 50 | Nombre maximum d'éléments (max 200). |
| cursor | string | — | Curseur de pagination (retourné dans next_cursor). |
// Lister les messages WhatsApp d'une instance
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/messages?limit=50', {
headers: { 'Authorization': 'Basic ' + credentials }
});
// Lister les messages WhatsApp d'une instance
$ch = curl_init('https://api.callistosignal.com/v1/whatsapp/{instanceCode}/messages?limit=50');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
'https://api.callistosignal.com/v1/whatsapp/{instanceCode}/messages?limit=50'
Réponse (200)
{
"data": [
{
"id": "wmsg_xxxxxx",
"to": "+22507XXXXXXXX",
"body": "Bonjour Aïcha",
"media_type": null,
"status": "delivered",
"sent_at": "2026-05-14T10:34:00Z",
"delivered_at": "2026-05-14T10:34:02Z",
"read_at": null,
"error_code": null,
"error_message": null
}
],
"next_cursor": null
}
Statut d'un message
GET /v1/whatsapp/messages/{messageId}
Paramètre de chemin : messageId — identifiant du message (ex. wmsg_xxxxxx).
// Consulter le statut d'un message WhatsApp
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/whatsapp/messages/wmsg_xxxxxx', {
headers: { 'Authorization': 'Basic ' + credentials }
});
// Consulter le statut d'un message WhatsApp
$ch = curl_init('https://api.callistosignal.com/v1/whatsapp/messages/wmsg_xxxxxx');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
https://api.callistosignal.com/v1/whatsapp/messages/wmsg_xxxxxx
Réponse (200)
{
"id": "wmsg_xxxxxx",
"to": "+22507XXXXXXXX",
"body": "Bonjour Aïcha",
"media_type": null,
"status": "delivered",
"sent_at": "2026-05-14T10:34:00Z",
"delivered_at": "2026-05-14T10:34:02Z",
"read_at": null,
"error_code": null,
"error_message": null
}
Valeurs possibles pour status : queued, sent, delivered, read, failed.
URL Monitor #
Vérifiez périodiquement la disponibilité de vos endpoints HTTP/HTTPS. Callisto interroge l'URL à l'intervalle configuré et déclenche une alerte email dès qu'elle devient lente ou inaccessible.
Configuration
- Connectez-vous à votre tableau de bord.
- Allez dans Monitoring → UpTime → Nouveau moniteur.
- Renseignez l'URL cible, la méthode HTTP (GET par défaut), l'intervalle (≥ 60 s) et le délai de timeout.
- Optionnel : codes de statut attendus (ex.
200, 204), en-têtes requis. - Adresse email d'alerte (par défaut celle du compte).
Notifications : alertes email automatiques en cas d'incident (downtime, code de statut inattendu, latence dépassée).
Tarification : inclus gratuitement avec votre compte Callisto.
API publique à venir — pour l'instant configurez via le tableau de bord.
Heartbeat Monitor #
Surveillez vos cron jobs et tâches planifiées. Vos jobs envoient un ping HTTP à une URL unique à la fin de chaque exécution ; Callisto vous alerte par email si le ping n'arrive pas dans l'intervalle attendu.
Configuration
- Allez dans Monitoring → Heartbeats → Nouveau heartbeat.
- Nommez le heartbeat (ex. "Backup nuit", "Sync inventaire").
- Définissez l'intervalle attendu (ex. 5 min) et le délai de grâce (ex. 1 min).
- Copiez l'URL de ping générée — elle est de la forme
https://ping.callistosignal.com/<uuid>. - Ajoutez un appel HTTP à cette URL à la fin de votre cron job.
Intégration
curl -fsS https://ping.callistosignal.com/<uuid>
*/5 * * * * /usr/bin/php /path/to/job.php && curl -fsS https://ping.callistosignal.com/<uuid>
// À la fin de votre job :
file_get_contents('https://ping.callistosignal.com/<uuid>');
Notifications : alertes email si aucun ping reçu dans intervalle + grâce.
Tarification : inclus gratuitement.
API publique pour gérer les heartbeats à venir — pour l'instant configurez via le tableau de bord.
Webhook Capture #
Inspectez en temps réel les requêtes HTTP entrantes pour déboguer vos intégrations tierces. Chaque webhook reçoit une URL unique ; tous les en-têtes, le corps et les paramètres de requête sont enregistrés.
Configuration
- Allez dans Monitoring → Webhooks → Nouveau webhook.
- Nommez le webhook (ex. "Stripe test", "Hub2 staging").
- Copiez l'URL générée — de la forme
https://webhook.callistosignal.com/hook/<token>(token = 32 caractères hexadécimaux). - Configurez ce webhook chez le service tiers que vous voulez tester (Stripe, Hub2, etc.).
- Les requêtes apparaissent en direct dans le tableau de bord, avec en-têtes, corps et paramètres de requête enregistrés.
Méthodes acceptées : GET, POST, PUT, PATCH, DELETE.
Affichage : chaque requête entrante est visible immédiatement dans le tableau de bord avec son timestamp, ses en-têtes, son corps et ses paramètres de requête.
Tarification : inclus gratuitement.
API publique pour lister les requêtes capturées à venir — pour l'instant consultez via le tableau de bord.
Vérifier le solde #
GET /v1/sms/balance// Consulter le solde du compte
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/sms/balance', {
headers: { 'Authorization': 'Basic ' + credentials }
});
// Consulter le solde du compte
$ch = curl_init('https://api.callistosignal.com/v1/sms/balance');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
https://api.callistosignal.com/v1/sms/balance
Statut d'un message #
GET /v1/sms/{id}// Consulter le statut d'un message
const credentials = btoa('ACCESS_KEY:ACCESS_SECRET');
const res = await fetch('https://api.callistosignal.com/v1/sms/msg_xxxxxx', {
headers: { 'Authorization': 'Basic ' + credentials }
});
// Consulter le statut d'un message
$ch = curl_init('https://api.callistosignal.com/v1/sms/msg_xxxxxx');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERPWD => 'ACCESS_KEY:ACCESS_SECRET',
]);
$response = curl_exec($ch);
curl -u 'ACCESS_KEY:ACCESS_SECRET' \
https://api.callistosignal.com/v1/sms/msg_xxxxxx
Statuts possibles
| Statut | Description |
|---|---|
| queued | Le message est en file d'attente |
| sent | Le message a été envoyé à l'opérateur |
| delivered | Le message a été livré au destinataire |
| failed | L'envoi du message a échoué |
Codes d'erreur #
| Code | Description |
|---|---|
400 |
Requête invalide - vérifiez les paramètres |
401 |
Non autorisé - clé API invalide ou manquante |
402 |
Crédits insuffisants |
404 |
Ressource non trouvée |
429 |
Limite de requêtes dépassée |
500 |
Erreur serveur interne |
Limites de requêtes #
Pour garantir la stabilité du service, les limites suivantes s'appliquent :
- 100 requêtes/minute pour les endpoints d'envoi de SMS
- 1000 requêtes/minute pour les endpoints de lecture
- 10 000 SMS/jour par défaut (contactez-nous pour augmenter)
Les en-têtes de réponse incluent des informations sur vos limites actuelles :
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1706789400