Enviar SMS

Una API para cada SMS que envías.

Configúralo en:
Cursor

Envía un mensaje o cien a través de la misma API de SMS. El SDK cuenta los segmentos antes del envío, elige GSM-7 o Unicode por ti, y cada envío es idempotente con un webhook en cada estado de entrega.

send-otp.ts
200 · 0.4s
import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });

const code = generateOtp();

const { data, error } = await bird.sms.send({
  from: "Bird",
  to:   "+15005550006",
  text: `Your Bird verification code is ${code}. Reply STOP to opt out.`,
}).safe();

if (error) throw error;
console.log(data.id);
// → "sms_4kT01Lq2m..."

Today at 2:14 PM

Hey Ada — your Bird sign-in code is 482917. It'll expire in 10 minutes. Don't share it with anyone.
482917
Delivered

Envía tu primer SMS en cinco minutos.

Desde el lenguaje que ya usas.

El envío es el núcleo de la API de SMS de Bird. El primer envío va a un destinatario de prueba autorizado (+15005550006), así que puedes desplegar una comprobación de CI y conectar webhooks antes de aprovisionar un número.

1
2
3
4
5
6
7
8
9
import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });

const { data, error } = await bird.sms.send({
  from: "Bird",
  to:   "+15005550006",
  text: "Hello from Node.",
}).safe();

Cinco cosas que no construyes tú mismo.

El mismo contrato en cada canal de Bird.

  1. 01

    Recuento de segmentos antes del envío.

    El SDK mide la longitud codificada y te dice cuántos segmentos cuesta un mensaje, así que un carácter perdido nunca divide en silencio un SMS en tres.

  2. 02

    GSM-7 y Unicode, decididos por ti.

    El texto plano viaja en GSM-7; un emoji o un alfabeto no latino convierte todo el mensaje a UCS-2. Bird elige la codificación y te avisa cuando un solo carácter cambia el coste.

  3. 03

    Agrupa en una sola llamada.

    Envía muchos mensajes independientes en una petición, cada uno con su propio destinatario y texto, validados como una unidad para que nunca envíes a medias.

  4. 04

    Idempotente por contrato.

    Cada envío acepta una clave de idempotencia, así que una petición reintentada tras un timeout devuelve el resultado original en lugar de mandar un SMS a alguien dos veces.

  5. 05

    Un webhook en cada cambio de estado.

    En cola, enviado, entregado, fallido. Cada uno firmado con HMAC, protegido contra repetición, idempotente, el mismo sobre en cada canal.

¿Ya envías desde otro sitio? Cambia el cliente, conserva la llamada.

La forma apenas cambia: cambia el cliente, conserva tu from, to y text, apunta tus webhooks a un solo endpoint. El mismo modelo de autenticación que tus envíos de email, voz y WhatsApp.

twilio.ts
Twilio
import twilio from "twilio";

const client = twilio(accountSid, authToken);

await client.messages.create({
  from: "+14155550172",
  to:   "+15005550006",
  body: "Your code is 123456.",
});
bird.ts
Bird
import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });

await bird.sms.send({
  from: "Bird",
  to:   "+15005550006",
  text: "Your code is 123456.",
});

Conoce el coste antes que el operador.

Un mensaje GSM-7 cabe en 160 caracteres por segmento; un solo emoji o carácter no latino convierte todo el mensaje a UCS-2 y lo reduce a 70. El SDK informa de la codificación y el recuento de segmentos en cada envío, así que la facturación nunca es una sorpresa y un mensaje concatenado siempre es una decisión deliberada.

segments.ts
200 · 1 segment
const { data } = await bird.sms.send({
  from: "Bird",
  to:   "+15005550006",
  text: "Your code is 123456.",
}).safe();

console.log(data.encoding); // → "GSM-7"
console.log(data.segments); // → 1

Un mensaje o cien, una llamada.

Agrupa mensajes independientes en una petición, cada uno con su propio destinatario y texto. El lote se valida como una unidad: un número incorrecto rechaza la llamada con un 422, así que nunca envías a medias. Una sola clave de idempotencia hace que toda la petición sea segura de reintentar.

reminders.ts
202 · batch
const { data: batch, error } = await bird.sms
  .sendBatch(
    users.map((u) => ({
      from: "Bird",
      to:   u.phone,
      text: `Hi ${u.name}, your appointment is tomorrow at ${u.time}.`,
    })),
    { idempotencyKey: `reminders-${runId}` },
  )
  .safe();

if (error) throw error;
console.log(`queued ${batch.data.length} messages`);

Sigue cada mensaje durante toda su vida.

Un envío devuelve 202 de inmediato; el resultado llega como webhook. Verifica una firma, conmuta según el tipo: el mismo sobre que ya gestionas para email, voz y WhatsApp.

app/api/webhooks/bird/route.ts
signed
import { bird } from "@/lib/bird";

export async function POST(req: Request) {
  const event = bird.webhooks.unwrap(
    await req.text(),
    Object.fromEntries(req.headers),
  );

  switch (event.type) {
    case "sms.delivered":
      await markDelivered(event.data.sms_id);
      break;
    case "sms.failed":
      await flag(event.data.to, event.data.reason);
      break;
  }

  return new Response(null, { status: 204 });
}

Los envíos fallidos y las respuestas STOP actualizan tu lista de supresión automáticamente, así que un número incorrecto nunca te cuesta dos veces.

  • sms.queuedAceptado por la API y en cola para la entrega al operador.
  • sms.sentEnviado al SMSC del operador de destino.
  • sms.deliveredAcuse de recibo recibido del operador (DLR).
  • sms.failedFallo permanente — rechazo del operador, número no válido o supresión activada.

Profundiza en la documentación.

Conecta webhooks, haz que cada envío sea seguro de reintentar con claves de idempotencia, y lee la referencia de errores para gestionar cada fallo de la forma correcta.

Preguntas frecuentes sobre el envío de SMS

¿Cuánto puede medir un SMS?+
Un mensaje GSM-7 cabe en 160 caracteres por segmento; cambiar a Unicode (UCS-2) para emojis o alfabetos no latinos lo reduce a 70. Los mensajes más largos se concatenan en varios segmentos, y el SDK informa del recuento antes de que envíes.
¿Puedo enviar a muchos destinatarios en una sola petición?+
Sí. Agrupa mensajes independientes en una sola llamada, cada uno con su propio destinatario y texto. El lote se valida como una unidad, y una clave de idempotencia cubre toda la petición.
¿Qué ocurre si reintento un envío tras un timeout?+
Pasa una clave de idempotencia y una petición reintentada devuelve el resultado original en lugar de enviar dos veces. Sin ella, un reintento se trata como un mensaje nuevo.
¿Cómo sé si un mensaje se entregó?+
Cada cambio de estado dispara un webhook firmado con HMAC — en cola, enviado, entregado o fallido — que lleva el acuse de recibo del operador y el recuento de segmentos.

Alrededor del 40 % del SMS comercial del mundo ya circula por Bird.

El envío es una capacidad de la API de SMS de Bird: los números, la recepción bidireccional, el cumplimiento, el enrutamiento y la analítica vienen con ella, sobre una infraestructura que llevamos una década operando.

Empieza con un canal.
Añade los demás cuando estés listo.

Una clave API de prueba es tuya de inmediato. El acceso a producción se desbloquea cuando añades un método de pago y verificas un remitente.

¿Usas Claude Code, Cursor o Codex? Copia un prompt de configuración y tu agente instalará el Bird CLI y las habilidades por ti. Elige el tuyo:

Cursor