ElementsChannel

SMS

SMS templates via channel.sms, transactional fx.send, and provider-managed OTP with fx.sendOtp / fx.verifyOtp.

SMS (channel.sms) delivers short text and provider-managed one-time codes. Pin an SMS driver (no default in any env), declare templates for app-owned messages, or call fx.sendOtp when the vendor owns the code.

For developers verifying phones — choose raw Channel OTP vs the otp plugin.

The one rule

SMS is opt-in: set drivers.channel.sms (e.g. "taqnyat") or boot has no SMS transport. Provider OTP needs a Verify-capable driver (taqnyat); app-owned codes use templates + fx.deliverOtp / the OTP plugin.

Smallest Example

Pin an SMS driver

oke.config.ts
import { defineConfig } from "okengine/config";

export default defineConfig({
  drivers: {
    channel: {
      sms: { prod: "taqnyat" },
    },
  },
});

Set TAQNYAT_BEARER_TOKEN (or TAQNYAT_TOKEN) and TAQNYAT_SENDER.

Declare a template and send

src/core/channel.ts
import { channel } from "okengine";
import { z } from "zod";

const sms = channel.sms({ sender: "ACME" });

export const orderShippedSms = sms.template("order.shipped", {
  locales: ["en"],
  schema: z.object({ tracking: z.string() }),
});
await fx.send(orderShippedSms, {
  to: "+15551234567",
  data: { tracking: "1Z999" },
});

Add a catalog body (text: "Shipped — track {{tracking}}") or accept the JSON fallback.

Or send a provider OTP

await fx.sendOtp({
  to: "+15551234567",
  requestId: fx.id(),
  lang: "en",
});

await fx.verifyOtp({
  to: "+15551234567",
  requestId, // same id
  code: userEnteredCode,
});

Effects record sends: ["sms-otp"]. Prefer otp({ mode: "provider" }) for /auth/otp/* routes.

Progressive Patterns

Transactional SMS through the same fx.send path as email:

const sms = channel.sms({ from: "ACME" });
export const alertSms = sms.template("ops.alert", {
  schema: z.object({ message: z.string() }),
});

await fx.send(alertSms, { to: phone, data: { message: "Disk 90%" } });

Drivers

Driver idOTP VerifyEnv
taqnyatyesTAQNYAT_BEARER_TOKEN / TAQNYAT_TOKEN + TAQNYAT_SENDER
msegatnoMSEGAT_USERNAME / MSEGAT_API_KEY / MSEGAT_SENDER
unifonicnoUNIFONIC_APPSID
consoleConfig id that opens no SMS driver

Boot errors (verbatim):

oke boot: taqnyat channel needs TAQNYAT_BEARER_TOKEN
oke boot: taqnyat channel needs TAQNYAT_SENDER
oke boot: msegat channel needs MSEGAT_USERNAME / MSEGAT_API_KEY / MSEGAT_SENDER
oke boot: unifonic channel needs UNIFONIC_APPSID

Provider OTP without a Verify driver:

channel: SMS driver "…" does not support provider-managed OTP; use exposeDevOtp locally or set drivers.channel.sms to "taqnyat"

No SMS bound:

channel: no SMS driver bound — bind drivers.channel.sms (e.g. taqnyat) to send provider OTP

Options Reference

channel.sms(options?)

Same medium options as email: from / sender.

.template(name, options?)

description · locales · schema — bodies in the catalog (text is typical for SMS).

Troubleshooting

Learn more

Next

On this page