Tutorials

How to Send OTP with Deno (2026)

Deno OTP tutorial using StartMessaging. Uses Deno.serve, native fetch, signed-cookie helpers and runs on Deno Deploy with zero infrastructure.

StartMessaging Team Updated

Deno + Deno Deploy give you a free-tier global edge for OTP login with zero servers. This tutorial wires StartMessaging.

Setup

# Install Deno
curl -fsSL https://deno.land/install.sh | sh

mkdir otp-deno && cd otp-deno
echo 'SM_API_KEY=sm_live_xxx' > .env

Deno.serve OTP App

// main.ts
import { load } from 'https://deno.land/std/dotenv/mod.ts';
const env = await load();
const apiKey = env['SM_API_KEY'] || Deno.env.get('SM_API_KEY')!;

// Unbiased 6-digit code from the Web Crypto API
function generateOtp(): string {
  const buf = new Uint32Array(1);
  do crypto.getRandomValues(buf); while (buf[0] >= 4294000000);
  return String(buf[0] % 1000000).padStart(6, '0');
}

async function smSend(phoneNumber: string) {
  const r = await fetch('https://api.startmessaging.com/otp/send', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
    body: JSON.stringify({
      phoneNumber,
      variables: { otp: generateOtp() },
      idempotencyKey: crypto.randomUUID(),
    }),
  });
  if (!r.ok) throw new Error('send failed');
  return (await r.json()).data; // { otpRequestId, messageId, status }
}

async function smVerify(requestId: string, otpCode: string) {
  const r = await fetch('https://api.startmessaging.com/otp/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
    body: JSON.stringify({ requestId, otpCode }),
  });
  return r.ok;
}

Deno.serve({ port: 3001 }, async (req) => {
  const url = new URL(req.url);
  if (req.method === 'POST' && url.pathname === '/auth/send-otp') {
    const { phoneNumber } = await req.json();
    const data = await smSend(phoneNumber);
    return Response.json({ requestId: data.otpRequestId });
  }
  if (req.method === 'POST' && url.pathname === '/auth/verify-otp') {
    const { requestId, otpCode } = await req.json();
    const ok = await smVerify(requestId, otpCode);
    return Response.json({ verified: ok }, { status: ok ? 200 : 401 });
  }
  return new Response('Not Found', { status: 404 });
});

Deploy to Deno Deploy

deployctl deploy --project=otp-deno main.ts
# add SM_API_KEY in dash.deno.com → settings → environment variables

FAQ

Need framework structure? Use Hono on top of Deno.

S

StartMessaging Team

StartMessaging Team

Related posts

Tutorials

How to Send OTP with Hono (2026)

Hono OTP tutorial using StartMessaging. Targets Cloudflare Workers, Bun and Node. Uses zValidator, JSON schema, signed-cookie session and middleware-based rate limiting.

Read more →