Developer Tutorials

How to Send OTP with Firebase Functions (2026)

Firebase Functions OTP tutorial using StartMessaging. Callable functions, Firestore for rate-limit, Firebase Auth custom-token issuance after OTP verification.

11 May 20268 min read

StartMessaging Team

Engineering

Firebase is convenient for app backends, but Firebase Phone Auth is not always the right pick for India. This tutorial replaces it with custom OTP via StartMessaging while keeping Firebase Auth for session management.

Why Not Firebase Phone Auth?

See our deep dive on Firebase Auth vs custom OTP.

Setup

firebase init functions
cd functions
npm install firebase-admin firebase-functions

Callable Functions

// functions/src/index.ts
import { initializeApp } from 'firebase-admin/app';
import { getAuth } from 'firebase-admin/auth';
import { onCall, HttpsError } from 'firebase-functions/v2/https';
import { defineSecret } from 'firebase-functions/params';
import { randomUUID } from 'node:crypto';

initializeApp();
const SM_KEY = defineSecret('SM_API_KEY');

export const sendOtp = onCall({ secrets: [SM_KEY] }, async (req) => {
  const { phoneNumber } = req.data;
  const r = await fetch('https://api.startmessaging.com/otp/send', {
    method: 'POST',
    headers: { 'X-API-Key': SM_KEY.value(), 'Content-Type': 'application/json' },
    body: JSON.stringify({ phoneNumber, idempotencyKey: randomUUID() }),
  });
  if (!r.ok) throw new HttpsError('unavailable', 'OTP send failed');
  return (await r.json()).data;
});

export const verifyOtp = onCall({ secrets: [SM_KEY] }, async (req) => {
  const { requestId, otpCode, phoneNumber } = req.data;
  const r = await fetch('https://api.startmessaging.com/otp/verify', {
    method: 'POST',
    headers: { 'X-API-Key': SM_KEY.value(), 'Content-Type': 'application/json' },
    body: JSON.stringify({ requestId, otpCode }),
  });
  if (!r.ok) throw new HttpsError('unauthenticated', 'invalid OTP');

  // mint Firebase Auth custom token
  const uid = `phone:${phoneNumber}`;
  const token = await getAuth().createCustomToken(uid, { phoneNumber });
  return { token };
});

Rate Limiting via Firestore

Use a Firestore document per phone with TTL field for hourly limits. Increment with FieldValue.increment(1).

Firebase Auth Custom Token

After successful verify, mint a custom token. Client signs in with signInWithCustomToken — and you have a Firebase Auth identity backed by your own OTP flow.

FAQ

Same idea on Cloud Run? See our Cloud Run guide.

Ready to Send OTPs?

Integrate StartMessaging in 5 minutes. No DLT registration required.