Sections
Documentation API
API SMS
Envoyez votre premier SMS canadien en moins de 5 minutes.
L’authentification, les clés API, la configuration et la signature des webhooks, les limites de débit, le SDK, le serveur MCP et les codes d’erreur généraux se trouvent sur la page Plateforme.
Démarrage rapide
- Créer un compte gratuit, puis ouvrez Clés API → Créer la clé dans le tableau de bord. La clé complète ne s’affiche qu’une fois, juste après sa création : copiez-la à ce moment.
- Commencez par une clé de test : elle fonctionne immédiatement, avant toute recharge, pour envoyer des messages de test et explorer l’API gratuitement.
- Rechargez votre solde par carte via Stripe. Les clés de production retournent 402 PAYMENT_REQUIRED jusqu’à la première recharge.
- Vérifiez votre numéro de téléphone en tant que propriétaire du compte. Un envoi réel nécessite un numéro de propriétaire vérifié.
- Achetez un numéro canadien pour l’envoi ; un envoi réel nécessite un numéro appartenant à votre compte.
- Enregistrez le consentement LCAP pour chaque numéro de téléphone que vous allez contacter.
- Envoyez votre premier message via l’API REST.
Numéros de téléphone
Recherchez les numéros canadiens disponibles, provisionnez-en un et utilisez-le comme champ from lors de l'envoi.
curl https://api.honkio.ca/v1/phone-numbers/search?area_codes=416 \
-H "Authorization: Bearer mk_live_YOUR_KEY"
# Response 200 (per result): what buying it charges now and monthly, in CAD cents
# { "phone_number": "+14165550100", "region": "Ontario",
# "upfront_cost_cents": 250, "activation_fee_cents": 100, "monthly_cost_cents": 250, ... }
# Provision a number
curl -X POST https://api.honkio.ca/v1/phone-numbers \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"phone_number": "+14165550100"}'
# Accounts hold a limited number of numbers. GET /v1/accounts/me reports
# phone_number_limit and phone_numbers_used: check them before buying, or
# handle the 403 NUMBER_LIMIT_REACHED that a purchase past the cap returns.
# Ask HonkIO staff to raise the limit. One request may be pending at a time.
curl -X POST https://api.honkio.ca/v1/phone-numbers/allowance-requests \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"requested_limit": 10, "reason": "Onboarding three new clinics this quarter"}'
# Response 201: { "status": "PENDING", "requested_limit": 10, ... }
# You are emailed if it is approved; the decision also shows in the dashboard.
# Check on it
curl https://api.honkio.ca/v1/phone-numbers/allowance-requests \
-H "Authorization: Bearer mk_live_YOUR_KEY"Consentement LCAP (requis avant l'envoi)
En vertu de la LCAP, vous devez enregistrer le consentement avant d'envoyer un message commercial à tout destinataire. L'API bloquera les envois vers des numéros de téléphone sans consentement valide (HTTP 451).
curl -X POST https://api.honkio.ca/v1/compliance/consents \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+1613XXXXXXX",
"consent_type": "express",
"source_description": "Website opt-in form",
"source_ip": "203.0.113.1"
}'Consentement tacite pour un client existant, le délai courant à partir de sa dernière transaction :
curl -X POST https://api.honkio.ca/v1/compliance/consents \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+1613XXXXXXX",
"consent_type": "implied",
"relationship_type": "purchase",
"last_transaction_date": "2025-11-04"
}'
# → { "status": "recorded", "phone_number": "+1613XXXXXXX", "expires_at": "2027-11-04T00:00:00.000Z" }Le consentement exprès n'expire jamais. Le consentement tacite expire après 2 ans selon l'art. 10(9) de la LCAP. Fournissez last_transaction_date pour que le délai de deux ans coure à partir de la relation réelle plutôt que du jour de l'enregistrement, ou indiquez directement expires_at si vous avez déjà calculé l'expiration. La réponse renvoie expires_at pour que vous puissiez le vérifier.
Envoi de SMS
Envoyez un message en utilisant un numéro provisionné. L'API valide le numéro de destination canadien, vérifie le consentement LCAP avant la livraison (vérification LNNTE du CRTC à venir).
# "from" is one of your HonkIO numbers; "to" is a real number you hold consent for
curl -X POST https://api.honkio.ca/v1/messages \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+1416XXXXXXX",
"to": "+1613XXXXXXX",
"body": "Hello from HonkIO! 🇨🇦"
}'Vérification de numéro de téléphone (OTP)
Utilisez l'API Verify pour confirmer la propriété d'un numéro de téléphone avant d'envoyer des messages commerciaux. Votre utilisateur final reçoit un code à usage unique par SMS; soumettez-le au point de terminaison de vérification pour confirmer.
# Start a verification (sends OTP SMS)
curl -X POST https://api.honkio.ca/v1/verify -H "Authorization: Bearer mk_live_YOUR_KEY" -H "Content-Type: application/json" -d '{
"from": "+1416XXXXXXX",
"to": "+1613XXXXXXX",
"code_length": 6,
"ttl_minutes": 10,
"app_name": "Acme"
}'
# Response: { "id": "clxxx...", "status": "pending", "code_length": 6, ... }
# Check the code submitted by your user
curl -X POST https://api.honkio.ca/v1/verify/clxxx.../check -H "Authorization: Bearer mk_live_YOUR_KEY" -H "Content-Type: application/json" -d '{ "code": "483721" }'
# Response 200: { "status": "verified", ... }
# Response 422: { "code": "VERIFICATION_INVALID_CODE", "attempts_remaining": 4 }
# Fetch status at any time
curl https://api.honkio.ca/v1/verify/clxxx... -H "Authorization: Bearer mk_live_YOUR_KEY"En mode test, le code est toujours composé de zéros selon la longueur choisie (ex. 000000 pour 6 chiffres). Aucun SMS n'est envoyé et rien n'est facturé. Chaque vérification retourne un champ « mode » valant « LIVE » ou « TEST » afin de distinguer une vérification simulée d'une vérification réelle.
Tarification
Les prix sont définis à l'exécution et peuvent changer sans nouvelle version : lisez-les plutôt que de les coder en dur. Tous les montants sont en cents CAD. L'envoi est facturé par partie SMS : message_cost_cents × le nombre de parties en lesquelles l'opérateur découpe le texte. Les parties sont comptées comme l'opérateur les compte : guillemets typographiques, tirets et points de suspension sont convertis en GSM-7 (160 caractères, puis 153 par partie), tandis que les émojis et la plupart des lettres accentuées imposent des parties Unicode (70, puis 67). Le montant est ajusté au décompte de l'opérateur après l'envoi. Un message refusé d'emblée par l'opérateur ne coûte rien, pas plus qu'un envoi vers un central réservé (555-XXXX et semblables), refusé ici ; un message accepté par l'opérateur mais non livré conserve ses frais. Un texte de plus de 10 parties est rejeté avec 422 MESSAGE_TOO_LONG avant toute facturation. verification_cost_cents couvre un OTP typique d'une seule partie ; un app_name long ou non GSM peut ajouter une partie. phone_number_activation_fee_cents est facturé une seule fois, avec le premier mois, pour chaque numéro provisionné, local ou sans frais, et n'est pas remboursé à la libération. inbound_message_cost_cents est facturé par partie pour chaque SMS reçu sur un numéro provisionné, quel que soit l'expéditeur ou l'opérateur, sauf les mots-clés STOP, START et HELP ; un message reçu est débité même si le solde passe sous zéro, ce qui suspend l'envoi jusqu'à la prochaine recharge.
# Current prices, in CAD cents
curl https://api.honkio.ca/v1/pricing \
-H "Authorization: Bearer mk_live_YOUR_KEY"
# Response 200:
# {
# "message_cost_cents": 3,
# "verification_upcharge_cents": 25,
# "verification_cost_cents": 28,
# "phone_number_upfront_cost_cents": 250,
# "phone_number_monthly_cost_cents": 250,
# "phone_number_activation_fee_cents": 100,
# "inbound_message_cost_cents": 3
# }Les requêtes en mode test sont tarifées de façon identique dans la réponse, mais ne sont jamais facturées : vous pouvez donc voir ce que coûterait une intégration sans rien dépenser.
Limites d’envoi
HonkIO est conçu pour la messagerie transactionnelle et relationnelle, pas pour les campagnes, et la délivrabilité de chaque client repose sur un profil opérateur partagé. Ces limites gardent le marketing de masse hors de la plateforme ; une clinique, un entrepreneur ou un SaaS qui envoie des codes ne les remarquera pas. Les limites d’envoi s’appliquent uniquement au mode réel ; la règle sur les raccourcisseurs de liens, les vérifications de destination réservée et injoignable, et le plafond de taille des diffusions s’appliquent aux deux modes.
- Plafond quotidien : les nouveaux comptes peuvent envoyer 250 messages réels par 24 heures glissantes. Il ne se lève pas de lui-même. 30 jours après votre premier message réel, vous pouvez demander un volume plus élevé depuis le tableau de bord ; l’approbation fixe 1 000 par jour ou le chiffre demandé. Les envois refusés renvoient 429 DAILY_LIMIT_REACHED avec votre limite et votre compte.
- Messages identiques : un même corps de message peut atteindre au plus 250 destinataires distincts par 24 heures (429 FANOUT_LIMIT_REACHED). Les messages personnalisés ne sont pas concernés.
- Débit par numéro : 60 messages par minute par numéro d’envoi, ce que les opérateurs canadiens accordent de toute façon à un numéro long (429 NUMBER_RATE_LIMITED avec Retry-After).
- Diffusions : jusqu’à 250 destinataires par diffusion de groupe et 3 diffusions par 24 heures (422 BROADCAST_TOO_LARGE, 429 BROADCAST_LIMIT_REACHED).
- Les raccourcisseurs de liens (bit.ly, tinyurl et similaires) sont refusés dans les deux modes, car les opérateurs les filtrent (422 LINK_SHORTENER_BLOCKED). Utilisez l’URL complète.
- Avertissement de livraison, puis pause automatique : si plus de 10 % de vos 50 derniers messages réels échouent chez l’opérateur, vous recevez un courriel (et l’événement account.delivery_warning) sans aucune pause. Si plus de 1 % des destinataires répondent STOP, ou plus de 5 % des messages sont rejetés par les opérateurs, sur vos envois récents, l’envoi réel est suspendu 24 heures et vous êtes avisé par courriel (403 SENDING_PAUSED avec l’heure de reprise ; l’événement account.sending_paused est émis).
- Rechargements : le solde ne peut dépasser 500 $ et les rechargements sont limités à 1 000 $ par 30 jours. Relevés sur demande.
- Plafond par destinataire : 30 messages vers un même destinataire par heure et 100 par 24 heures (429 RECIPIENT_RATE_LIMITED avec Retry-After). Une conversation bidirectionnelle n’en approche jamais ; un script qui réessaie le même numéro, oui.
- Les messages non livrés sont facturés : un message accepté par l’opérateur mais non livré conserve ses frais. Un central réservé (555-XXXX, centraux N11 comme 411 ou 911, codes de test des opérateurs, centraux commençant par 0 ou 1) est refusé sans frais avec 422 RESERVED_DESTINATION, en mode test aussi, et un indicatif régional réservé (555, 911 et semblables) comme tout numéro non canadien. Tout ce qui réessaie devrait envoyer un en-tête Idempotency-Key afin qu’une nouvelle tentative ne devienne jamais un second débit. Une heure de dépenses inhabituelles déclenche un courriel et l’événement account.spend_warning.
- Numéros injoignables : après 3 échecs consécutifs chez l’opérateur vers un même numéro en 30 jours, tous clients HonkIO confondus, les envois vers ce numéro sont refusés sans frais (422 UNDELIVERABLE_NUMBER avec le nombre d’échecs, la date d’inscription et la date d’expiration) pendant 90 jours, puis réessayés au cas où le numéro aurait été réattribué.
curl https://api.honkio.ca/v1/send-limit \
-H "Authorization: Bearer mk_live_YOUR_KEY"
# → { "daily_limit": 250, "sent_last_24h": 12, "remaining": 238,
# "recipient_rate_per_hour": 30, "recipient_rate_per_day": 100,
# "probation": { "ends_at": "2026-09-26T14:02:11.000Z", "eligible_to_request": false },
# "paused_until": null, "requests": [] }Consultez vos limites et votre utilisation avec GET /v1/send-limit, et déposez une demande avec POST /v1/send-limit/requests. Chaque chiffre ci-dessus est une valeur par défaut de la plateforme qui peut être relevée par compte.
Événements webhook
Voici les événements SMS, de désabonnement et de numéro de téléphone. L’inscription d’un point de terminaison, l’enveloppe de chaque événement, les nouvelles tentatives et les signatures sont décrites dans Webhooks de la plateforme.
Chaque charge utile est signée avec HMAC-SHA256 : vérifiez l’en-tête X-HonkIO-Signature. Un évènement message.received contient l’expéditeur, votre numéro, le texte, keyword_action (traitement STOP/START), ainsi que segment_count et cost_cents, le montant facturé pour ce message. Un évènement message.sent contient carrier_message_id, l’identifiant que l’opérateur a attribué au message, avec les deux mêmes champs de facturation.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "message.delivered",
"created": "2026-09-19T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"message_id": "clxxxmessagexxxxxxxxxxxxx",
"status": "delivered",
"message_status": "DELIVERED",
"to": "+1613XXXXXXX",
"from": "+1416XXXXXXX",
"errors": []
}
}
// Headers: X-HonkIO-Signature, X-HonkIO-Timestamp, X-HonkIO-EventUn même message_id peut émettre message.failed (seulement si l’échec était CARRIER_UNAVAILABLE ; un échec INSUFFICIENT_BALANCE n’émet aucun webhook) puis de nouveau message.queued, puis message.sent, lorsqu’une nouvelle tentative avec la même Idempotency-Key relance un message ayant échoué avant d’atteindre l’opérateur.
Chaque évènement, tel que votre point de terminaison le reçoit. Les exemples sont caviardés : identifiants, numéros et adresses sont fictifs. Des champs peuvent s’ajouter avec le temps, ignorez donc ceux que vous ne reconnaissez pas.
message.queued
Un message sortant a été accepté et facturé, et va être remis à l’opérateur.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "message.queued",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"message_id": "clxxxmessagexxxxxxxxxxxxx",
"from": "+1416XXXXXXX",
"to": "+1613XXXXXXX",
"status": "QUEUED",
"message_status": "QUEUED"
}
}| Champ de data | Signification |
|---|---|
| message_id | L’identifiant HonkIO du message, tel que renvoyé par POST /v1/messages ou listé par GET /v1/messages. |
| from | Votre numéro HonkIO d’où le message est parti, au format E.164. |
| to | Le numéro du destinataire, au format E.164. |
| status | Le statut du message à ce moment, en majuscules (la même valeur que message_status). |
| message_status | Le statut HonkIO du message, en majuscules : QUEUED, SENDING, DELIVERED, FAILED, UNDELIVERED ou RECEIVED. |
message.sending
Réservé : rarement, voire jamais envoyé. Il ne se déclenche que si un accusé final de l’opérateur indique le statut sending, ce qui n’est pas attendu en pratique.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "message.sending",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"message_id": "clxxxmessagexxxxxxxxxxxxx",
"status": "sending",
"message_status": "SENDING",
"to": "+1613XXXXXXX",
"from": "+1416XXXXXXX",
"errors": []
}
}| Champ de data | Signification |
|---|---|
| message_id | L’identifiant HonkIO du message, tel que renvoyé par POST /v1/messages ou listé par GET /v1/messages. |
| status | Le statut propre à l’opérateur tiré de son accusé, en minuscules (par exemple delivered, sending_failed, delivery_failed ou expired). |
| message_status | Le statut HonkIO du message, en majuscules : QUEUED, SENDING, DELIVERED, FAILED, UNDELIVERED ou RECEIVED. |
| to | Le numéro du destinataire, au format E.164. |
| from | Votre numéro HonkIO d’où le message est parti, au format E.164. |
| errors | Ce que l’opérateur a signalé, sous forme de liste ; vide s’il n’a rien signalé. |
| errors[].code | Le code d’erreur de l’opérateur, tel quel. |
| errors[].title | Une brève description de l’erreur. |
| errors[].detail | Plus de détails, quand l’opérateur en donne. |
message.sent
L’opérateur a accepté le message pour livraison. Déclenché au retour de l’appel d’envoi, pas par un accusé.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "message.sent",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"message_id": "clxxxmessagexxxxxxxxxxxxx",
"from": "+1416XXXXXXX",
"to": "+1613XXXXXXX",
"status": "SENDING",
"message_status": "SENDING",
"carrier_message_id": "40319xxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"segment_count": 1,
"cost_cents": 3
}
}| Champ de data | Signification |
|---|---|
| message_id | L’identifiant HonkIO du message, tel que renvoyé par POST /v1/messages ou listé par GET /v1/messages. |
| from | Votre numéro HonkIO d’où le message est parti, au format E.164. |
| to | Le numéro du destinataire, au format E.164. |
| status | Le statut du message à ce moment, en majuscules (la même valeur que message_status). |
| message_status | Le statut HonkIO du message, en majuscules : QUEUED, SENDING, DELIVERED, FAILED, UNDELIVERED ou RECEIVED. |
| carrier_message_id | L’identifiant attribué au message par l’opérateur, pour les demandes de soutien. |
| segment_count | Le nombre de segments SMS du message, qui est la base de sa facturation. |
| cost_cents | Ce que le message vous a coûté, en cents canadiens. |
message.delivered
L’accusé de l’opérateur indique que le message a atteint l’appareil.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "message.delivered",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"message_id": "clxxxmessagexxxxxxxxxxxxx",
"status": "delivered",
"message_status": "DELIVERED",
"to": "+1613XXXXXXX",
"from": "+1416XXXXXXX",
"errors": []
}
}| Champ de data | Signification |
|---|---|
| message_id | L’identifiant HonkIO du message, tel que renvoyé par POST /v1/messages ou listé par GET /v1/messages. |
| status | Le statut propre à l’opérateur tiré de son accusé, en minuscules (par exemple delivered, sending_failed, delivery_failed ou expired). |
| message_status | Le statut HonkIO du message, en majuscules : QUEUED, SENDING, DELIVERED, FAILED, UNDELIVERED ou RECEIVED. |
| to | Le numéro du destinataire, au format E.164. |
| from | Votre numéro HonkIO d’où le message est parti, au format E.164. |
| errors | Ce que l’opérateur a signalé, sous forme de liste ; vide s’il n’a rien signalé. |
| errors[].code | Le code d’erreur de l’opérateur, tel quel. |
| errors[].title | Une brève description de l’erreur. |
| errors[].detail | Plus de détails, quand l’opérateur en donne. |
message.failed
Le message n’est pas parti. Trois formes selon l’endroit de l’échec : un échec au passage à l’opérateur (CARRIER_UNAVAILABLE, CARRIER_TIMEOUT, CARRIER_ERROR, INVALID_PHONE_NUMBER, NOT_A_MOBILE_NUMBER) porte error_code et error_message mais pas de tableau errors ; un accusé de l’opérateur porte son statut brut, un tableau errors et un error_code, mais pas de error_message ; un envoi interrompu par un redémarrage du serveur (error_code STALE_QUEUED) ne porte ni to ni from. Un échec pour INSUFFICIENT_BALANCE ne déclenche aucun webhook.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "message.failed",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"message_id": "clxxxmessagexxxxxxxxxxxxx",
"from": "+1416XXXXXXX",
"to": "+1613XXXXXXX",
"status": "FAILED",
"message_status": "FAILED",
"error_code": "INVALID_PHONE_NUMBER",
"error_message": "The destination is not a valid phone number."
}
}| Champ de data | Signification |
|---|---|
| message_id | L’identifiant HonkIO du message, tel que renvoyé par POST /v1/messages ou listé par GET /v1/messages. |
| status | Le statut propre à l’opérateur tiré de son accusé, en minuscules (par exemple delivered, sending_failed, delivery_failed ou expired). |
| message_status | Le statut HonkIO du message, en majuscules : QUEUED, SENDING, DELIVERED, FAILED, UNDELIVERED ou RECEIVED. |
| to | Le numéro du destinataire, au format E.164. |
| from | Votre numéro HonkIO d’où le message est parti, au format E.164. |
| error_code | Le code d’erreur HonkIO de l’échec, le même que celui du message dans l’API. |
| error_message | Une explication lisible de error_code. |
| errors | Ce que l’opérateur a signalé, sous forme de liste ; vide s’il n’a rien signalé. |
| errors[].code | Le code d’erreur de l’opérateur, tel quel. |
| errors[].title | Une brève description de l’erreur. |
| errors[].detail | Plus de détails, quand l’opérateur en donne. |
message.undelivered
L’opérateur a pris le message mais n’a pas pu le livrer : bloqué, expiré, ou appareil injoignable.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "message.undelivered",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"message_id": "clxxxmessagexxxxxxxxxxxxx",
"status": "delivery_failed",
"message_status": "UNDELIVERED",
"to": "+1613XXXXXXX",
"from": "+1416XXXXXXX",
"errors": [
{
"code": "40002",
"title": "Blocked as spam",
"detail": "The destination carrier blocked the message."
}
]
}
}| Champ de data | Signification |
|---|---|
| message_id | L’identifiant HonkIO du message, tel que renvoyé par POST /v1/messages ou listé par GET /v1/messages. |
| status | Le statut propre à l’opérateur tiré de son accusé, en minuscules (par exemple delivered, sending_failed, delivery_failed ou expired). |
| message_status | Le statut HonkIO du message, en majuscules : QUEUED, SENDING, DELIVERED, FAILED, UNDELIVERED ou RECEIVED. |
| to | Le numéro du destinataire, au format E.164. |
| from | Votre numéro HonkIO d’où le message est parti, au format E.164. |
| errors | Ce que l’opérateur a signalé, sous forme de liste ; vide s’il n’a rien signalé. |
| errors[].code | Le code d’erreur de l’opérateur, tel quel. |
| errors[].title | Une brève description de l’erreur. |
| errors[].detail | Plus de détails, quand l’opérateur en donne. |
message.received
Quelqu’un a texté l’un de vos numéros HonkIO. Les réponses STOP, START et HELP arrivent aussi ici, avec keyword_action qui indique ce qui en a été fait.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "message.received",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"message_id": "clxxxmessagexxxxxxxxxxxxx",
"from": "+1613XXXXXXX",
"to": "+1416XXXXXXX",
"body": "Yes, see you at 3",
"keyword_action": "ignored",
"segment_count": 1,
"cost_cents": 1,
"message_status": "RECEIVED"
}
}| Champ de data | Signification |
|---|---|
| message_id | L’identifiant HonkIO du message, tel que renvoyé par POST /v1/messages ou listé par GET /v1/messages. |
| from | Le numéro qui vous a texté, au format E.164. |
| to | Votre numéro HonkIO qui a reçu le texto, au format E.164. |
| body | Le texte du message. |
| keyword_action | Ce que HonkIO a fait d’un mot-clé de conformité, d’après le premier mot du texte : opted_out (STOP et semblables, suivi d’un évènement opt_out.recorded), reinstated (START ou UNSTOP après un désabonnement, suivi d’un évènement opt_out.reinstated), help (HELP, INFO ou AIDE ; la réponse automatique a été envoyée), ou ignored. |
| segment_count | Le nombre de segments SMS du message, qui est la base de sa facturation. |
| cost_cents | Ce que la réception du message vous a coûté, en cents canadiens. |
| message_status | Le statut HonkIO du message, en majuscules : QUEUED, SENDING, DELIVERED, FAILED, UNDELIVERED ou RECEIVED. |
opt_out.recorded
Un abonné a répondu à l’un de vos numéros par un mot-clé de désabonnement (une réponse dont le premier mot est STOP, STOPALL, UNSUBSCRIBE, CANCEL, END ou QUIT), et les messages vers lui depuis ce numéro sont maintenant bloqués. Se déclenche uniquement pour une réponse par mot-clé : un désabonnement enregistré avec POST /v1/compliance/opt-outs ne le déclenche pas.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "opt_out.recorded",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"phone_number": "+1613XXXXXXX",
"from_number": "+1416XXXXXXX",
"keyword": "STOP"
}
}| Champ de data | Signification |
|---|---|
| phone_number | L’abonné qui a texté le mot-clé, au format E.164 : la personne à qui cesser ou recommencer d’écrire. |
| from_number | Votre numéro HonkIO qui a reçu le mot-clé, au format E.164. Un désabonnement vaut pour les messages envoyés depuis ce numéro. |
| keyword | La réponse de l’abonné, rognée et en majuscules, par exemple STOP ou STOP PLEASE. La réponse entière, pas seulement le mot-clé : elle a été reconnue par son premier mot. |
opt_out.reinstated
Un abonné désabonné a répondu START ou UNSTOP, vous pouvez donc de nouveau lui écrire depuis ce numéro. Se déclenche uniquement pour une réponse par mot-clé, et seulement si un désabonnement existait : un START de quelqu’un qui ne s’était jamais désabonné est un simple message.received.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "opt_out.reinstated",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"phone_number": "+1613XXXXXXX",
"from_number": "+1416XXXXXXX",
"keyword": "START"
}
}| Champ de data | Signification |
|---|---|
| phone_number | L’abonné qui a texté le mot-clé, au format E.164 : la personne à qui cesser ou recommencer d’écrire. |
| from_number | Votre numéro HonkIO qui a reçu le mot-clé, au format E.164. Un désabonnement vaut pour les messages envoyés depuis ce numéro. |
| keyword | La réponse de l’abonné, rognée et en majuscules, par exemple START. La réponse entière, pas seulement le mot-clé : elle a été reconnue par son premier mot. |
phone_number.suspended
Le loyer mensuel n’a pas pu être prélevé, le numéro a donc été suspendu. Rechargez votre solde pour le récupérer avant la fin du délai de grâce.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "phone_number.suspended",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"phone_number": "+1416XXXXXXX",
"reason": "insufficient_balance",
"monthly_cost_cents": 299
}
}| Champ de data | Signification |
|---|---|
| phone_number | Votre numéro HonkIO, au format E.164. |
| reason | Toujours insufficient_balance : le loyer du mois n’a pas pu être prélevé. |
| monthly_cost_cents | Le loyer mensuel du numéro, en cents canadiens. |
phone_number.released
Le numéro a quitté votre compte et ne peut pas être récupéré. Cessez d’y acheminer quoi que ce soit.
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "phone_number.released",
"created": "2026-09-24T12:00:00.000Z",
"account_id": "clxxxaccountxxxxxxxxxxxxx",
"livemode": true,
"data": {
"phone_number": "+1416XXXXXXX",
"reason": "customer_released"
}
}| Champ de data | Signification |
|---|---|
| phone_number | Votre numéro HonkIO, au format E.164. |
| reason | suspended_grace_expired quand une suspension a dépassé son délai de grâce, customer_released quand vous l’avez libéré vous-même, admin_released quand le personnel de HonkIO l’a libéré. |
Codes d'erreur
Les codes ci-dessous sont propres aux SMS, aux numéros de téléphone, à la vérification et à la LCAP. Tout appel peut aussi répondre avec les codes généraux du tableau d’erreurs de la plateforme, comme VALIDATION_ERROR, INSUFFICIENT_BALANCE et NOT_FOUND.
| HTTP | Code | Signification |
|---|---|---|
| 403 | NUMBER_LIMIT_REACHED | Le compte a atteint sa limite de numéros de téléphone |
| 403 | PHONE_NUMBER_NOT_OWNED | Le numéro from n’est pas provisionné sur ce compte. |
| 403 | ALLOW_LIST_BLOCKED | Le destinataire ne figure pas sur la liste ALLOW de cette clé API |
| 403 | DENY_LIST_BLOCKED | Le destinataire figure sur la liste DENY de cette clé API |
| 403 | SEND_LIMIT_REQUEST_TOO_EARLY | Les demandes de volume s’ouvrent une fois la période probatoire du compte terminée. |
| 404 | VERIFICATION_NOT_FOUND | Identifiant de vérification introuvable ou non associé à ce compte |
| 404 | CONTACT_NOT_FOUND | Contact introuvable |
| 404 | CONTACT_GROUP_NOT_FOUND | Groupe de contacts introuvable |
| 404 | CONTACT_GROUP_MEMBER_NOT_FOUND | Ce contact n’est pas membre de ce groupe |
| 404 | CONTACT_LIST_NOT_FOUND | Liste de contacts introuvable |
| 404 | CONTACT_LIST_ENTRY_NOT_FOUND | Entrée de liste introuvable |
| 409 | VERIFICATION_ALREADY_VERIFIED | Ce numéro a déjà été vérifié |
| 409 | PURCHASE_IN_PROGRESS | Un autre achat de numéro est en cours. Réessayez sous peu |
| 409 | ALLOWANCE_REQUEST_PENDING | Une demande d'allocation est déjà en attente d'examen |
| 409 | PHONE_NUMBER_SUSPENDED | Les frais mensuels de ce numéro n’ont pas pu être prélevés. Rechargez votre solde pour le réactiver. |
| 409 | SEND_LIMIT_REQUEST_PENDING | Une demande de volume est déjà en attente d’examen. |
| 409 | IDEMPOTENCY_KEY_REUSED | La même clé Idempotency-Key a été envoyée avec un to, from ou body différent. |
| 409 | CONTACT_ALREADY_EXISTS | Un contact avec ce numéro de téléphone existe déjà |
| 409 | CONTACT_GROUP_ALREADY_EXISTS | Un groupe de contacts avec ce nom existe déjà |
| 409 | CONTACT_GROUP_MEMBER_EXISTS | Le contact est déjà membre de ce groupe |
| 409 | CONTACT_LIST_ALREADY_EXISTS | Une liste de contacts avec ce nom existe déjà |
| 409 | CONTACT_LIST_ENTRY_EXISTS | Cette entrée existe déjà dans la liste |
| 410 | VERIFICATION_EXPIRED | Le code de vérification a expiré |
| 422 | NON_CANADIAN_NUMBER | Numéro E.164 canadien invalide |
| 422 | UNDELIVERABLE_NUMBER | Le numéro a échoué trois fois de suite chez l’opérateur (tous clients confondus) ; refusé sans frais pendant 90 jours. |
| 422 | NOT_A_MOBILE_NUMBER | Le numéro de destination est une ligne fixe ou un numéro VoIP. L’opérateur le refuse avant l’envoi ; rien n’est facturé. |
| 422 | RESERVED_DESTINATION | Le numéro de destination appartient à un central réservé (555-XXXX, N11, codes de test des opérateurs). Refusé avant tout envoi ; rien n’est facturé. |
| 422 | MESSAGE_TOO_LONG | Le texte dépasserait la limite de 10 parties SMS de l'opérateur (≈1 530 caractères GSM-7 ou 670 caractères Unicode). Rien n'est facturé |
| 422 | VERIFICATION_INVALID_CODE | Code incorrect. attempts_remaining indique le nombre de tentatives restantes |
| 422 | INVALID_ALLOWANCE_REQUEST | L'allocation demandée doit dépasser votre limite actuelle |
| 422 | LINK_SHORTENER_BLOCKED | Les raccourcisseurs de liens sont refusés car les opérateurs les filtrent. Utilisez l’URL complète |
| 422 | BROADCAST_TOO_LARGE | Groupe de contacts trop grand pour une seule diffusion (250 membres par défaut). Divisez-le et envoyez par lots |
| 422 | CANNOT_ERASE_OWN_NUMBER | Ce numéro appartient à votre compte. L’effacement vise uniquement le numéro d’un abonné |
| 422 | TOO_MANY_AREA_CODES | Recherchez au plus 25 indicatifs régionaux à la fois |
| 422 | INVALID_PHONE_NUMBER | Numéro de téléphone E.164 invalide |
| 422 | CONTACT_LIST_ENTRY_INVALID | Chaque entrée doit spécifier exactement l’un des champs phone_number, contact_id ou contact_group_id |
| 429 | RECIPIENT_RATE_LIMITED | Plus de 30 messages vers un même destinataire en une heure ou 100 en une journée ; réessayez après l’en-tête Retry-After. |
| 429 | VERIFICATION_MAX_ATTEMPTS | Trop de tentatives incorrectes. Cette vérification est verrouillée |
| 429 | DAILY_LIMIT_REACHED | Limite d’envoi quotidienne atteinte (les détails indiquent votre limite et le compte). Demandez un volume plus élevé une fois admissible |
| 429 | FANOUT_LIMIT_REACHED | Ce message identique a déjà atteint le nombre maximal de destinataires distincts autorisé sur 24 heures |
| 429 | NUMBER_RATE_LIMITED | Ce numéro d’envoi a atteint sa limite par minute. Réessayez sous peu |
| 429 | BROADCAST_LIMIT_REACHED | Limite de diffusions atteinte pour ce compte au cours des 24 dernières heures |
| 451 | OPT_OUT_BLOCKED | Le destinataire s’est désabonné. L’envoi est donc bloqué par la loi. |
| 451 | NO_CONSENT | Pas de consentement LCAP valide en dossier |
| 451 | CONSENT_EXPIRED | Consentement tacite expiré (limite LCAP de 2 ans) |
| 451 | DNCL_BLOCKED | Numéro sur la LNNTE du CRTC sans exemption applicable (à venir; non retourné actuellement) |
| 501 | DNCL_COMING_SOON | La vérification de la liste nationale de numéros de télécommunication exclus du CRTC n’est pas encore disponible. |
| 501 | TOLLFREE_800_COMING_SOON | Les numéros 1-800 ne sont pas encore disponibles. Choisissez un autre préfixe sans frais ou un numéro local. |
| 502 | CARRIER_ERROR | L’opérateur a renvoyé une erreur lors de l’envoi. |
| 502 | PROVISIONING_FAILED | L’opérateur n’a pas pu compléter cet achat de numéro. Rien n’a été facturé. |
| 502 | NUMBER_SEARCH_FAILED | La recherche de numéros est temporairement indisponible. |
| 502 | RELEASE_FAILED | L’opérateur n’a pas accepté la libération. Le numéro vous appartient toujours ; réessayez sous peu |
| 503 | CARRIER_UNAVAILABLE | L’opérateur est injoignable ; rien n’a été envoyé ni facturé. Réessayez sous peu. |
| 503 | CARRIER_TIMEOUT | L’opérateur n’a pas répondu à temps : le message a peut-être été envoyé, ou non. Rien n’est facturé. Vérifiez le statut du message avant de l’envoyer de nouveau : une nouvelle tentative avec la même Idempotency-Key renvoie le message en échec au lieu de l’envoyer une seconde fois. |
HonkIO