Skip to content
SMS SDK
Esc
↑↓navigate↵open⌘Jpreview
On this page

Telnyx

Send and receive SMS and MMS through the Telnyx Messaging API v2 with the SMS SDK telnyx() adapter: setup, senders, webhooks, errors, and limits.

The telnyx() adapter sends SMS and MMS through the Telnyx Messaging API v2 and verifies Telnyx’s Ed25519-signed messaging webhooks. To compare providers, see Choose a provider.

Support status

Supported. Requests, responses, the error catalog, and webhook signing follow Telnyx’s official documentation and its official Node SDK, and the adapter passes the shared contract tests. Limits to know:

  • No validity period. Telnyx’s send request has no expiry field, so validityPeriodSec throws UnsupportedFieldError.
  • Alphanumeric senders need messagingProfileId on the adapter.
  • Webhooks are verified with a public key, not the API key. The URL is not signed.
  • Webhook timestamps must be within 300 seconds of now by default.

Setup

npm install @opencoredev/sms-sdk
pnpm add @opencoredev/sms-sdk
yarn add @opencoredev/sms-sdk
bun add @opencoredev/sms-sdk
nub add @opencoredev/sms-sdk
aube add @opencoredev/sms-sdk
Variable Required Used for
TELNYX_API_KEY Yes API v2 key, sent as a Bearer token. Create it in Mission Control under API Keys.
TELNYX_FROM Unless you send from a profile Default sender: a Telnyx number, short code, or alphanumeric sender ID.
TELNYX_MESSAGING_PROFILE_ID For alphanumeric senders Messaging profile ID sent with every message.
TELNYX_PUBLIC_KEY For webhooks Base64 Ed25519 public key from Mission Control, Keys & Credentials, Public Key.

The adapter reads no environment variables itself; the examples and the doctor CLI use these names. Keep the API key on the server.

import { createSmsClient } from "@opencoredev/sms-sdk";
import { telnyx } from "@opencoredev/sms-sdk/telnyx";

const sms = createSmsClient({
  adapters: [
    telnyx({
      apiKey: process.env.TELNYX_API_KEY ?? "",
      from: "+15550100001",
      // Needed only for alphanumeric senders:
      // messagingProfileId: process.env.TELNYX_MESSAGING_PROFILE_ID,
    }),
  ],
});

const result = await sms.send({ to: "+14155550123", body: "Your order has shipped." });
console.log(result.providerId); // the Telnyx message ID (data.id)

telnyx() throws ConfigurationError at startup when apiKey is empty. Two more options exist for tests and proxies: baseUrl (default https://api.telnyx.com) and fetch. To test without a Telnyx account, see Test without a provider.

The adapter calls POST /v2/messages with a JSON body. Delivery comes from data.to[0].status, usually queued. A 2xx without data.id is an unknown outcome.

Senders

Sender Write Sent as
Long code or toll-free number "+15550100001" from
Short code { shortCode: "12345" } from
Alphanumeric sender ID { senderId: "Acme" } from, plus messaging_profile_id from the adapter
Messaging profile number pool { messagingService: "<profile id>" } messaging_profile_id, with no from

An alphanumeric sender without messagingProfileId on the adapter fails local validation before any request. In Telnyx, assign each number to a messaging profile before it sends.

US A2P traffic to mobile numbers needs 10DLC registration, toll-free numbers need verification, and a short code works in one country only. Alphanumeric senders can’t reach the US, Canada, or Puerto Rico, and recipients can’t reply to them. Some countries, such as the UK and France, require sender ID registration in advance. Telnyx’s sender type guide covers the rules. SMS SDK does not check them before sending; see Registration and consent.

Features

Feature Telnyx
MMS Yes, sent with type: "MMS"
Scheduling (sendAt) Yes, from any sender
Validity period No
Per-message webhookUrl Yes, sent as webhook_url

Provider options

Pass other POST /v2/messages fields in providerOptions.telnyx:

import { sms } from "./sms";

await sms.send({
  to: "+14155550123",
  body: "Your order has shipped.",
  webhookUrl: "https://example.com/webhooks/sms/telnyx",
  providerOptions: {
    telnyx: { encoding: "gsm7", webhookFailoverUrl: "https://backup.example.com/webhooks/sms/telnyx" },
  },
});
Option Telnyx field Type
subject subject string, the subject of an MMS
webhookFailoverUrl webhook_failover_url http or https URL
useProfileWebhooks use_profile_webhooks boolean, Telnyx default true
autoDetect auto_detect boolean, Telnyx default false
encoding encoding "auto" | "gsm7" | "ucs2". With "gsm7", Telnyx answers 400 if a character has no GSM-7 form.
extra any other field Record<string, string | number | boolean>, sent as is

Unknown keys and wrong types throw before any request, and the options go out only when the telnyx adapter sends. extra cannot set the fields SMS SDK owns: to, from, messaging_profile_id, text, media_urls, type, webhook_url, and send_at. See providerOptions for how options interact with fallback and idempotency.

Webhooks

import { parseSmsWebhook, WebhookSignatureError } from "@opencoredev/sms-sdk/webhooks";
import { db } from "./db";

export async function POST(request: Request): Promise<Response> {
  try {
    const event = await parseSmsWebhook({
      provider: "telnyx",
      request,
      credentials: { publicKey: process.env.TELNYX_PUBLIC_KEY ?? "" },
    });
    if (event.type === "message.delivered" || event.type === "message.undelivered") {
      await db.messages.updateStatus(event.providerId, event.type, event.errorCode);
    } else if (event.type === "recipient.opted_out") {
      await db.suppressions.add(event.from);
    }
    return new Response(null, { status: 200 });
  } catch (error) {
    if (error instanceof WebhookSignatureError) return new Response("Invalid signature", { status: 401 });
    throw error;
  }
}
  • Credential: your account’s Ed25519 public key. A key that is not 32 bytes of base64 fails with invalid_credentials.
  • Point Telnyx at it: for status, pass webhookUrl per message or set the webhook URL on the messaging profile. For inbound, set the inbound webhook URL on the profile the number belongs to.
  • Signing: telnyx-signature-ed25519 covers `${telnyx-timestamp}|${rawBody}`. The URL is not signed, so proxies don’t affect verification and there is no publicUrl option.
  • Replay window: 300 seconds either side of now by default. Older or future timestamps fail with stale_timestamp. Change it with toleranceSec.

SMS SDK reads message.received, message.sent, and message.finalized events. Status comes from data.payload.to[0].status:

Telnyx status Event
queued, sending message.queued
sent, delivery_unconfirmed message.sent
delivered message.delivered
sending_failed, delivery_failed, expired message.undelivered, or message.filtered with error 40002, 40003, or 40322
Other events and statuses, such as read unrecognized
message.received message.received, or a recipient.* event from STOP and HELP keywords (source: "keyword")

Telnyx sends no opt-out flag, so opt-outs come from keyword detection. dedupeKey is telnyx:{data.id}, the webhook event ID. providerId is the message ID, data.payload.id, which matches result.providerId.

Limitations

  • No validityPeriodSec. For an expiry, use Twilio, Plivo, Vonage, or Sinch.
  • Error 40008 is not mapped to message.filtered, because Telnyx’s pages disagree on its meaning. It stays message.undelivered.

Error codes

The code comes from errors[0].code in the response.

Telnyx response Category Falls back
10009, 10010, 20001, 20002, 20003, 20006, 20008; 401 or 403 without a listed code auth Yes
10011, 40318 (queue full) rate_limited Yes, after retries
40305, 40306, 40308, 40315, 40320, 40321, 40329, 40330 sender Yes
20013, 20100, 40309, 40312, 40314, 40331, 40333 (spend limit) account Yes
40301, 40310, 40319 recipient No
40300 (blocked due to STOP), 40322 (blocked content) compliance Never
Any other 4xx request No
429 without code 10011 or 40318 unknown Never
5xx, network error, timeout, 2xx without data.id unknown Never

Telnyx does not document a Retry-After header, but SMS SDK honors one on a rate limit. error.provider.requestId holds the x-request-id header. For adapter authors, the subpath also exports buildTelnyxRequest, interpretTelnyxResponse, telnyxRejectionCategory, and telnyxDelivery.

Official documentation

Checked on 2026-10-08. The full evidence list is in PROVIDERS.md.

Next steps