> ## 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.

# Enviar y recibir mensajes

> Envía tu primer SMS o mensaje de WhatsApp a través de la API de Orbit y recibe las respuestas entrantes vía webhook en un solo recorrido end-to-end con código.

# Enviar y recibir mensajes

Esta guía te lleva desde una clave de API hasta un flujo de mensajes bidireccional que funciona: envía un mensaje saliente, sigue su entrega y recibe la respuesta en tu propio servidor. El ejemplo usa SMS — el mismo patrón de tres pasos (enviar → seguir → recibir) se aplica a WhatsApp, RCS, Viber y correo electrónico, cada uno en su propio endpoint.

**Harás lo siguiente:**

1. [Enviar un mensaje](#1-enviar-un-mensaje)
2. [Seguir la entrega](#2-seguir-la-entrega)
3. [Recibir mensajes entrantes](#3-recibir-mensajes-entrantes)
4. [Responder a un mensaje entrante](#4-responder-a-un-mensaje-entrante)

## Requisitos previos

* Una clave de API desde **Ajustes → Claves de API**. Utiliza una clave sandbox (`dv_test_sk_…`) mientras construyes — los envíos sandbox son gratuitos y simulados, y devuelven comprobantes de entrega deterministas para que puedas ejercer tanto los caminos de éxito como los de error. Cambia a una clave live (`dv_live_sk_…`) para producción.
* Un número remitente que pueda enviar en el canal que uses. Para SMS es un número compatible con SMS que posees (búscalo y cómpralo vía la [API de Numbers](/api-reference/numbers) o desde **Dashboard → Números**). Si omites `from`, Orbit elige un remitente elegible para el destino.
* Una URL HTTPS pública para el paso de [recepción](#3-recibir-mensajes-entrantes). Cualquier herramienta de túnel funciona mientras desarrollas.

Todas las solicitudes van a una única URL base — el sandbox es el mismo host, seleccionado por tu clave, no por otro dominio:

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

Cada solicitud lleva tu clave en el encabezado `X-API-Key`.

## 1. Enviar un mensaje

Envía un SMS con `POST /messages/sms`. Solo `to` y `body` son obligatorios; `from` es opcional.

```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 respuesta es `202 Accepted` — el mensaje se persiste y se pone en cola para entrega, aún no entregado al operador. Los campos viven bajo `data`; `meta` lleva el `request_id` que debes registrar para soporte.

```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"
  }
}
```

El `id` (`msg_` seguido de 32 caracteres hexadecimales) es el handle para todas las llamadas posteriores — las consultas de estado, los webhooks de entrega y la traza del mensaje lo usan. Las respuestas sandbox añaden `"test_mode": true` a `meta`.

<Note>
  Envía siempre una `Idempotency-Key` en los envíos. Reproducir la misma clave y el mismo cuerpo dentro de las 24 horas devuelve la respuesta original en lugar de enviar un duplicado; reproducirla con un cuerpo distinto devuelve `409 IDEMPOTENCY_KEY_REUSED`.
</Note>

### Otros canales

Cada canal tiene su propio endpoint bajo el prefijo `/messages`, con una forma de cuerpo adaptada a ese canal. No hay una única ruta polimórfica por canal — elige el endpoint que coincida con tu canal:

| Canal              | Endpoint                  | Referencia                                              |
| ------------------ | ------------------------- | ------------------------------------------------------- |
| SMS                | `POST /messages/sms`      | [API de Mensajería](/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)                          |
| Correo electrónico | `POST /messages/email`    | [Canal de correo electrónico](/channels/email)          |

## 2. Seguir la entrega

Un mensaje en cola recorre un ciclo de estados antes de llegar al destinatario:

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

Tienes dos formas de seguirlo:

**Consulta** (poll) el mensaje por id:

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

**Suscríbete a webhooks** (recomendado — sin polling). Por cada transición de estado se dispara un evento, cada uno llevando el `id` del mensaje y el nuevo `status`:

* `message.sent` — aceptado por el operador
* `message.delivered` — entrega confirmada al terminal
* `message.failed` — fallo terminal (el `status` del payload distingue `failed`, `undelivered`, `expired` y `submitted_no_receipt`; `error_code` / `error_message` llevan el motivo del proveedor cuando está presente)

Registra un endpoint webhook una sola vez y deja que los eventos fluyan:

```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 evento de entrega se ve así:

```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"
  }
}
```

Verifica el encabezado `X-Orbit-Signature` antes de confiar en cualquier payload, y deduplica por el `id` del evento — la entrega es al menos una vez (at-least-once). Consulta [Seguridad de webhooks](/webhooks/security) para el fragmento de verificación.

## 3. Recibir mensajes entrantes

Cuando alguien responde a tu número (o te escribe primero), Orbit registra un mensaje entrante y — si estás suscrito a `message.received` en el paso anterior — lo envía por POST a tu URL de 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"
  }
}
```

El mensaje entrante también es consultable — lista todo lo recibido con el filtro `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>
  El enrutamiento entrante es automático para los números que posees en Orbit — una respuesta a cualquiera de tus números remitentes se captura y, con una suscripción `message.received`, se entrega a tu webhook. No hace falta cablear URLs entrantes por número.
</Note>

## 4. Responder a un mensaje entrante

Responder es solo otro envío, dirigido de vuelta al `from` entrante. Intercambia `to` y `from` y llama a `POST /messages/sms` de nuevo:

```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."
  }'
```

Ambos mensajes comparten una conversación, así que una vez que existe el hilo puedes extraer el intercambio completo con el filtro `conversation_id` en `GET /messages`.

## Errores comunes

Todo error usa la misma forma — coincide en `error.code` (una constante en MAYÚSCULAS) y registra `meta.request_id`:

| Código                 | HTTP | Significado                                                              | Solución                                 |
| ---------------------- | ---- | ------------------------------------------------------------------------ | ---------------------------------------- |
| `INVALID_API_KEY`      | 401  | Clave revocada, entorno equivocado o error de tipeo                      | Revisa **Ajustes → Claves de API**       |
| `INVALID_PHONE_NUMBER` | 422  | `to` no es un E.164 válido o no es alcanzable                            | Valida el número antes de enviar         |
| `NOT_SMS_CAPABLE`      | 422  | El remitente no es compatible con SMS (por ejemplo, toll-free sin 10DLC) | Registra o cambia el número              |
| `INSUFFICIENT_BALANCE` | 402  | Cartera por debajo del mínimo del canal                                  | Recarga tu cartera                       |
| `RATE_LIMITED`         | 429  | Demasiados envíos                                                        | Respeta `details.retry_after` (segundos) |
| `VALIDATION_ERROR`     | 422  | Forma del cuerpo incorrecta                                              | Lee `details.issues` por cada campo      |

Lista completa: [Códigos de error](/reference/error-codes).

## Próximos pasos

* [Referencia de la API de Mensajería](/api-reference/endpoints/messaging) — cada endpoint y campo de mensaje
* [Ciclo de vida del estado de los mensajes](/api-reference/messages-status-lifecycle) — el conjunto completo de estados por canal
* [Visión general de Webhooks](/webhooks/overview) — reintentos, garantías de entrega y catálogo de eventos
* [Integración de la API](/guides/api-integration) — sandbox, idempotencia, paginación y SDK para cada canal
* [Límites de velocidad](/guides/rate-limits) — límites por canal y encabezados de reintento
