> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Envoyer et recevoir des messages

> Envoyez votre premier SMS ou message WhatsApp via l'API Orbit et recevez les réponses entrantes par webhook dans un guide rapide de bout en bout avec du code.

# Envoyer et recevoir des messages

Ce guide vous emmène d'une clé API à un flux de messages bidirectionnel qui fonctionne : envoyez un message sortant, suivez sa livraison et recevez la réponse sur votre propre serveur. L'exemple utilise le SMS — le même schéma en trois étapes (envoyer → suivre → recevoir) s'applique à WhatsApp, RCS, Viber et e-mail, chacun sur son propre endpoint.

**Vous allez :**

1. [Envoyer un message](#1-envoyer-un-message)
2. [Suivre la livraison](#2-suivre-la-livraison)
3. [Recevoir des messages entrants](#3-recevoir-des-messages-entrants)
4. [Répondre à un message entrant](#4-répondre-à-un-message-entrant)

## Prérequis

* Une clé API depuis **Paramètres → Clés API**. Utilisez une clé sandbox (`dv_test_sk_…`) pendant le développement — les envois sandbox sont gratuits et simulés, et renvoient des accusés de livraison déterministes pour que vous puissiez exercer les deux chemins, succès et erreur. Passez à une clé live (`dv_live_sk_…`) pour la production.
* Un numéro expéditeur capable d'envoyer sur le canal utilisé. Pour le SMS, c'est un numéro SMS-compatible que vous possédez (recherchez-le et achetez-le via l'[API Numbers](/api-reference/numbers) ou via **Dashboard → Numéros**). Si vous omettez `from`, Orbit choisit un expéditeur éligible pour la destination.
* Une URL HTTPS publique pour l'étape de [réception](#3-recevoir-des-messages-entrants). Tout outil de tunnel convient en développement.

Toutes les requêtes visent une seule URL de base — le sandbox utilise le même hôte, sélectionné par votre clé et non par un autre domaine :

```
https://api.orbit.devotel.io/api/v1
```

Chaque requête porte votre clé dans l'en-tête `X-API-Key`.

## 1. Envoyer un message

Envoyez un SMS avec `POST /messages/sms`. Seuls `to` et `body` sont obligatoires ; `from` est facultatif.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/messages/sms \
  -H "X-API-Key: dv_test_sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-conf-98421" \
  -d '{
    "to": "+14155552671",
    "from": "+18005551234",
    "body": "Your order #1234 has shipped. Reply STATUS for tracking."
  }'
```

La réponse est `202 Accepted` — le message est persisté et mis en file pour la livraison, pas encore remis à l'opérateur. Les champs vivent sous `data` ; `meta` porte le `request_id` que vous devez journaliser pour le support.

```json theme={null}
{
  "data": {
    "id": "msg_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
    "status": "queued",
    "channel": "sms",
    "direction": "outbound",
    "segments": 1
  },
  "meta": {
    "request_id": "req_xyz789",
    "timestamp": "2026-07-20T00:00:00Z"
  }
}
```

L'`id` (`msg_` suivi de 32 caractères hexadécimaux) est l'identifiant utilisé par tous les appels qui suivent — les requêtes de statut, les webhooks de livraison et la trace du message l'utilisent tous. Les réponses sandbox ajoutent `"test_mode": true` à `meta`.

<Note>
  Envoyez toujours une `Idempotency-Key` lors des envois. Rejouer la même clé et le même corps dans les 24 heures renvoie la réponse originale au lieu d'envoyer un doublon ; rejouer avec un corps différent renvoie `409 IDEMPOTENCY_KEY_REUSED`.
</Note>

### Autres canaux

Chaque canal a son propre endpoint sous le préfixe `/messages`, avec une forme de corps adaptée à ce canal. Il n'y a pas de route unique polymorphe sur le canal — choisissez l'endpoint qui correspond à votre canal :

| Canal    | Endpoint                  | Référence                                           |
| -------- | ------------------------- | --------------------------------------------------- |
| SMS      | `POST /messages/sms`      | [API Messaging](/api-reference/endpoints/messaging) |
| WhatsApp | `POST /messages/whatsapp` | [Canal WhatsApp](/channels/whatsapp)                |
| RCS      | `POST /messages/rcs`      | [Canal RCS](/channels/rcs)                          |
| Viber    | `POST /messages/viber`    | [Canal Viber](/channels/viber)                      |
| E-mail   | `POST /messages/email`    | [Canal e-mail](/channels/email)                     |

## 2. Suivre la livraison

Un message en file traverse un cycle de statuts avant d'atteindre le destinataire :

```
queued → sending → sent → delivered   (ou failed / undelivered)
```

Vous avez deux moyens de le suivre :

**Interrogez** le message par id :

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/messages/msg_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \
  -H "X-API-Key: dv_test_sk_YOUR_KEY"
```

**Abonnez-vous aux webhooks** (recommandé — pas de polling). Un événement est émis à chaque transition de statut, chacun portant l'`id` du message et le nouveau `status` :

* `message.sent` — accepté par l'opérateur
* `message.delivered` — livraison confirmée au terminal
* `message.failed` — échec terminal (le `status` du payload distingue `failed`, `undelivered`, `expired` et `submitted_no_receipt` ; `error_code` / `error_message` portent la raison du fournisseur lorsqu'elle est présente)

Enregistrez un endpoint webhook une seule fois, puis laissez les événements arriver :

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/webhooks \
  -H "X-API-Key: dv_test_sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/orbit",
    "events": ["message.sent", "message.delivered", "message.failed", "message.received"],
    "secret": "whsec_your_signing_secret"
  }'
```

Un événement de livraison ressemble à ceci :

```json theme={null}
{
  "id": "evt_abc123",
  "type": "message.delivered",
  "created_at": "2026-07-20T12:00:00Z",
  "data": {
    "message_id": "msg_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
    "channel": "sms",
    "status": "delivered",
    "is_terminal": true,
    "timestamp": "2026-07-20T12:00:00Z"
  }
}
```

Vérifiez l'en-tête `X-Orbit-Signature` avant d'accepter une payload, et dédupliquez sur l'`id` de l'événement — la livraison est au moins une (at-least-once). Voir [Sécurité des webhooks](/webhooks/security) pour l'extrait de validation.

## 3. Recevoir des messages entrants

Lorsque quelqu'un répond à votre numéro (ou vous écrivent en premier), Orbit enregistre un message entrant et — si vous êtes abonné à `message.received` à l'étape précédente — le POST vers votre URL webhook :

```json theme={null}
{
  "id": "evt_def456",
  "type": "message.received",
  "created_at": "2026-07-20T12:01:00Z",
  "data": {
    "message_id": "msg_inb_9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c",
    "channel": "sms",
    "from": "+14155552671",
    "to": "+18005551234",
    "body": "STATUS"
  }
}
```

Le message entrant est aussi requêtable — listez tout ce que vous avez reçu avec le filtre `direction=inbound` :

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/messages?direction=inbound&channel=sms" \
  -H "X-API-Key: dv_test_sk_YOUR_KEY"
```

<Note>
  Le routage entrant est automatique pour les numéros que vous possédez sur Orbit — une réponse à l'un de vos numéros expéditeurs est capturée et, avec un abonnement `message.received`, livrée à votre webhook. Aucun branchement d'URL entrant par numéro n'est nécessaire.
</Note>

## 4. Répondre à un message entrant

Répondre n'est qu'un autre envoi, adressé en retour au `from` entrant. Échangez `to` et `from` et appelez `POST /messages/sms` une nouvelle fois :

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/messages/sms \
  -H "X-API-Key: dv_test_sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+14155552671",
    "from": "+18005551234",
    "body": "Order #1234 is out for delivery, arriving today by 5pm."
  }'
```

Les deux messages partagent une conversation, donc une fois le fil de discussion créé vous pouvez récupérer l'intégralité de l'échange avec le filtre `conversation_id` sur `GET /messages`.

## Erreurs courantes

Toute erreur utilise la même forme — faites correspondre sur `error.code` (une constante en MAJUSCULES) et journalisez `meta.request_id` :

| Code                   | HTTP | Signification                                                                | Solution                                   |
| ---------------------- | ---- | ---------------------------------------------------------------------------- | ------------------------------------------ |
| `INVALID_API_KEY`      | 401  | Clé révoquée, mauvais environnement ou faute de frappe                       | Vérifiez **Paramètres → Clés API**         |
| `INVALID_PHONE_NUMBER` | 422  | `to` n'est pas un E.164 valide ou pas joignable                              | Validez le numéro avant l'envoi            |
| `NOT_SMS_CAPABLE`      | 422  | L'expéditeur n'est pas compatible SMS (par ex. numéro sans frais sans 10DLC) | Enregistrez ou changez le numéro           |
| `INSUFFICIENT_BALANCE` | 402  | Portefeuille en dessous du minimum du canal                                  | Rechargez votre portefeuille               |
| `RATE_LIMITED`         | 429  | Trop d'envois                                                                | Respectez `details.retry_after` (secondes) |
| `VALIDATION_ERROR`     | 422  | Forme de corps incorrecte                                                    | Lisez `details.issues` pour chaque champ   |

Liste complète : [Codes d'erreur](/reference/error-codes).

## Prochaines étapes

* [Référence de l'API Messaging](/api-reference/endpoints/messaging) — chaque endpoint et champ de message
* [Cycle de vie du statut des messages](/api-reference/messages-status-lifecycle) — l'ensemble complet des statuts par canal
* [Aperçu des webhooks](/webhooks/overview) — relances, garanties de livraison et catalogue d'événements
* [Intégration de l'API](/guides/api-integration) — sandbox, idempotence, pagination et SDK pour chaque canal
* [Limites de débit](/guides/rate-limits) — limites par canal et en-têtes de relance
