پیامک و OTP کاوه‌نگار

kavenegar-otpراهنما

ارسال OTP با Verify Lookup کاوه‌نگار: قالب تأییدشده، نرمال‌سازی شماره ۰۹، بررسی return.status و نمونه TypeScript آماده. کلید API فقط سمت سرور.

کی به کار می‌آد

  • ورود با کد یک‌بارمصرف
  • تأیید شماره موبایل ایرانی
  • ارسال پیامک قالبی کاوه‌نگار
  • وقتی مدل API خارجی SMS می‌نویسه

برچسب‌ها

راهنماپیامکOTPکاوه‌نگار

راهنما فرانت‌متر نداره و خودکار فعال نمیشه؛ از CLAUDE.md یا AGENTS.md به آن لینک بدید تا مدل در هر جلسه بخوندش.

Kavenegar SMS / OTP (implementation guide)

Kavenegar is an Iranian SMS gateway. The Verify Lookup endpoint sends a pre-approved template SMS containing one or more dynamic tokens (for example OTP codes). All calls are plain GET requests authenticated via an API key embedded in the URL path.

Hand this document to an AI or developer to wire OTP / verify SMS into any Node.js or Next.js project.


Environment variables

Add these to your .env / .env.local:

1KAVENEGAR_API_KEY=<your-api-key-from-kavenegar-panel>2KAVENEGAR_VERIFY_TEMPLATE=<template-name-approved-in-kavenegar-panel>
  • KAVENEGAR_API_KEY: found in your Kavenegar dashboard under API Keys.

  • KAVENEGAR_VERIFY_TEMPLATE: the exact name of the template you created and got approved in the Kavenegar panel (e.g. verify).

Keep the API key server-side only. Never expose it to the browser.


API endpoint

1GET https://api.kavenegar.com/v1/{API_KEY}/verify/lookup.json

All parameters are passed as query string parameters.

Required query params

ParamTypeDescription
receptorstringRecipient phone number (see Phone format)
tokenstringThe primary dynamic value (e.g. the OTP code)
templatestringName of the approved template in your Kavenegar account

Optional query params

ParamTypeDescription
token2stringSecond dynamic value in the template
token3stringThird dynamic value
token10stringSlot 10 dynamic value
token20stringSlot 20 dynamic value
type`'sms' \'call'`Delivery channel; defaults to SMS
tagstringCustom tag for tracking

Response shape

1{2  "return": {3    "status": 200,4    "message": "تایید شد"5  },6  "entries": [7    {8      "messageid": 123456789,9      "message": "your otp is 45123",10      "status": 5,11      "statustext": "ارسال به مخابرات",12      "sender": "10004346",13      "receptor": "09123456789",14      "date": 1715000000,15      "cost": 116    }17  ]18}
  • return.status === 200 means the request was accepted.

  • Any other return.status value is an error; return.message describes it.

  • HTTP-level errors (non-2xx) also indicate failure.


Phone number format

Kavenegar accepts these formats for receptor:

Input formatExpected by KavenegarNotes
989123456789 (E.164 without +)09123456789Strip 98, prepend 0
+98912345678909123456789Strip +98, prepend 0
0912345678909123456789Already correct
International non-IR00[country][number]Prepend 00 if not already present

TypeScript implementation

1// lib/kavenegar.ts23export interface SendOTPParams {4  receptor: string;5  token: string;6  template?: string; // overrides KAVENEGAR_VERIFY_TEMPLATE env var7  token2?: string;8  token3?: string;9  token10?: string;10  token20?: string;11  type?: "sms" | "call";12  tag?: string;13}1415export interface KavenegarResponse {16  return: {17    status: number;18    message: string;19  };20  entries?: Array<{21    messageid: number;22    message: string;23    status: number;24    statustext: string;25    sender: string;26    receptor: string;27    date: number;28    cost: number;29  }>;30}3132export async function sendOTPWithKavenegar(33  params: SendOTPParams34): Promise<KavenegarResponse> {35  const apiKey = process.env.KAVENEGAR_API_KEY;36  const defaultTemplate = process.env.KAVENEGAR_VERIFY_TEMPLATE;3738  if (!apiKey) throw new Error("KAVENEGAR_API_KEY is not set");39  if (!defaultTemplate) throw new Error("KAVENEGAR_VERIFY_TEMPLATE is not set");4041  const baseUrl = `https://api.kavenegar.com/v1/${apiKey}/verify/lookup.json`;42  const searchParams = new URLSearchParams({43    receptor: params.receptor.replace(/\s/g, ""),44    token: params.token,45    template: params.template ?? defaultTemplate,46  });4748  if (params.token2) searchParams.set("token2", params.token2);49  if (params.token3) searchParams.set("token3", params.token3);50  if (params.token10) searchParams.set("token10", params.token10);51  if (params.token20) searchParams.set("token20", params.token20);52  if (params.type) searchParams.set("type", params.type);53  if (params.tag) searchParams.set("tag", params.tag);5455  const response = await fetch(`${baseUrl}?${searchParams.toString()}`, {56    method: "GET",57  });5859  if (!response.ok) {60    throw new Error(61      `Kavenegar HTTP error: ${response.status} ${response.statusText}`62    );63  }6465  const data: KavenegarResponse = await response.json();6667  if (data.return?.status !== 200) {68    throw new Error(69      `Kavenegar rejected request: ${data.return?.message ?? "Unknown error"}`70    );71  }7273  return data;74}7576/** Normalises a phone number to the format Kavenegar expects. */77export function toKavenegarReceptor(phone: string): string {78  const cleaned = phone.replace(/\D/g, "");7980  // Iranian mobile: 989xxxxxxxxx → 09xxxxxxxxx81  if (cleaned.startsWith("98") && cleaned.length === 12) {82    return `0${cleaned.slice(2)}`;83  }8485  // Already local Iranian format86  if (cleaned.startsWith("09") && cleaned.length === 11) {87    return cleaned;88  }8990  // International: ensure 00 prefix91  if (cleaned.startsWith("00")) return cleaned;92  return `00${cleaned}`;93}

Usage example

1import { sendOTPWithKavenegar, toKavenegarReceptor } from "@/lib/kavenegar";23const otp = "45123";4const phone = "989123456789";56await sendOTPWithKavenegar({7  receptor: toKavenegarReceptor(phone),8  token: otp,9  // template: "custom-template", // optional override10});

Error handling notes

  • Always check data.return.status === 200 after a successful HTTP response. Kavenegar returns HTTP 200 even for logical errors, putting the real status in return.status.

  • Common non-200 Kavenegar status codes:

    • 401: invalid API key

    • 404: receptor invalid

    • 411: template not found

    • 417: template tokens mismatch


Security checklist

  • [ ] KAVENEGAR_API_KEY is server-side only.

  • [ ] OTP is generated and stored server-side; never accept a client-supplied code as truth.

  • [ ] Rate-limit send attempts per phone and per IP.

  • [ ] Expire OTPs (e.g. 2–5 minutes) and limit verification attempts.

  • [ ] Prefer the approved Verify Lookup template over raw SMS for OTP flows.

  • [ ] Do not log full OTP codes or API keys.


Official resources

نمونه

پرامپت: «OTP را با کاوه‌نگار بفرست»

بدون مهارت

SMS خام با متن آزاد و شماره به فرمت +98

با مهارت

verify/lookup با template تأییدشده و receptor به شکل ۰۹xxxxxxxxx

نمونه برای نشان دادن جهت تغییره؛ خروجی واقعی به مدل و پرامپت شما بستگی داره.

نصب

  1. با CLI

    این دستور فایل را در docs/kavenegar-otp.md می‌نویسه. CLI به init نیاز نداره؛ فقط باید داخل پوشه‌ی پروژه باشید.

    $npx vibefarsi add kavenegar-otp
  2. دستی

    محتوای تب kavenegar-otp.md را کپی کنید و در مسیر ابزار خودتون بگذارید:

    • Claude Codeفایل را در docs/kavenegar-otp.md بگذارید و این خط را به CLAUDE.md اضافه کنید:@docs/kavenegar-otp.md
    • Cursorدر .cursor/rules/kavenegar-otp.mdc با alwaysApply: true بالای فایل
    • Codex و بقیهمتن را در AGENTS.md بگذارید یا از همان‌جا به فایل لینک بدید
    کپی کل فایلregistry json

می‌خواید همه‌ی قوانین را یک‌جا داشته باشید؟ قوانین فارسی برای CLAUDE.md خلاصه‌ی همه‌ی مهارت‌ها در یک صفحه‌ست و قوانین کرافت رابط طرف طراحی را پوشش میده. npx vibefarsi init هر دو را داخل پروژه می‌نویسه.