مستندات / REST API

REST API

فعال‌سازی، JWT، اندپوینت‌ها و نمونه کد چندزبانه.

ویدیو آموزشی

آموزش تصویری بخش «REST API»

در حال ضبط و جمع‌آوری ویدیو

نسخه ویدیویی این آموزش پس از آماده‌شدن در همین قسمت نمایش داده می‌شود.

نشانی پایه (Base URL) همه مسیرها نسبت به این آدرس هستند: https://YOUR-SITE.com/wp-json/darban/v1 تا API را در پنل فعال نکنید، این مسیرها در دسترس نیستند.

۱) فعال‌سازی API در پنل

  1. ورود به بخش API از منوی دربان وارد بخش «API توسعه‌دهنده» شوید.
  2. فعال‌سازی تیک «فعال‌سازی API» را بزنید و ذخیره کنید.
  3. تولید کلیدها برای کلید API و کلید مخفی روی «تولید» کلیک کنید. کلید مخفی فقط سمت سرور بماند و داخل اپ موبایل قرار نگیرد.
  4. امنیت پیشنهادی برای سایت واقعی
    • الزام کلید API با هدر X-Darban-Key
    • در صورت نیاز، امضای HMAC
    • محدودیت تعداد درخواست در دقیقه
    • در صورت نیاز، فهرست IP مجاز یا مسدود
تنظیم پیش‌فرض توضیح
فعال‌سازی APIخاموشثبت مسیرهای REST
کلید APIبرای هدر X-Darban-Key
کلید مخفیامضای JWT و HMAC (فقط سرور)
عمر توکن دسترسی۳۶۰۰ ثانیهتقریباً ۱ ساعت
عمر توکن تازه‌سازی~۱۴ روزبرای گرفتن توکن جدید بدون ورود دوباره
محدودیت نرخ۶۰درخواست در دقیقه برای هر IP (۰ = بدون سقف)

۲) مدل احراز هویت

  • عمومی: ارسال OTP، تأیید OTP، ثبت‌نام، ورود با رمز، تازه‌سازی توکن
  • با توکن: خروج، پروفایل و به‌روزرسانی پروفایل — با هدر Authorization: Bearer <access_token>
  • جایگزین هدر: X-Darban-Authorization: Bearer …
امضای HMAC (اختیاری) اگر در پنل الزام امضا را روشن کنید: HMAC-SHA256("{timestamp}.{raw_body}", api_secret) و هدرهای X-Darban-Timestamp و X-Darban-Signature را بفرستید. اختلاف ساعت بیش از ۵ دقیقه رد می‌شود.

۳) شکل پاسخ موفق ورود

در ورود موفق معمولاً کاربر و اطلاعات نشست برمی‌گردد:

{
  "success": true,
  "code": "login_success",
  "message": "…",
  "user": {
    "id": 12,
    "display_name": "علی رضایی",
    "email": "ali@example.com",
    "username": "09121234567",
    "roles": ["customer"],
    "phone": "989121234567",
    "verified": true
  },
  "session_data": {
    "jwt_token": "<access JWT>",
    "refresh_token": "<refresh JWT>",
    "wordpress_cookie": false,
    "expires_at": 1710000000,
    "token_type": "Bearer"
  }
}

۴) فهرست اندپوینت‌ها

روش مسیر احراز بدنه
POSTotp/sendعمومیphone, dial_code
POSTotp/resendعمومیphone, dial_code
POSTotp/verifyعمومیphone, dial_code, code
POSTotp/registerعمومیticket, fields{…}
POSTloginعمومیidentifier, password, dial_code
POSTtoken/refreshعمومیrefresh_token
POSTlogoutتوکن
GETprofileتوکن
POSTprofile/updateتوکنfields{…}
POSTprofile/completeتوکنticket, fields{…}
POSTprofile/verify-mobileتوکنticket, phone, dial_code, code
نکته otp/resend همان کار ارسال کد را انجام می‌دهد. قبل از ارسال دوباره، مقدار تأخیر پیشنهادی در پاسخ (معمولاً حدود ۶۰ ثانیه) را رعایت کنید.

۵) سناریو: ورود با OTP (کاربر موجود)

  1. ارسال کد با POST /otp/send
  2. تأیید کد با POST /otp/verify و ذخیره توکن‌ها
  3. درخواست‌های محافظت‌شده با Bearer
  4. تازه‌سازی توکن وقتی access منقضی شد

POST /otp/send

curl -X POST "https://YOUR-SITE.com/wp-json/darban/v1/otp/send" \
  -H "Content-Type: application/json" \
  -H "X-Darban-Key: YOUR_API_KEY" \
  -H "User-Agent: MyApp/1.0" \
  -d "{\"phone\":\"09121234567\",\"dial_code\":\"98\"}"
const base = 'https://YOUR-SITE.com/wp-json/darban/v1';

const res = await fetch(`${base}/otp/send`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
    'User-Agent': 'MyApp/1.0',
  },
  body: JSON.stringify({
    phone: '09121234567',
    dial_code: '98',
  }),
});

const data = await res.json();
console.log(data.code, data.user_exists, data.security_data);
<?php
$base = 'https://YOUR-SITE.com/wp-json/darban/v1';
$body = json_encode([
    'phone' => '09121234567',
    'dial_code' => '98',
]);

$ch = curl_init($base . '/otp/send');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-Darban-Key: YOUR_API_KEY',
        'User-Agent: MyApp/1.0',
    ],
    CURLOPT_POSTFIELDS => $body,
    CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
import requests

base = "https://YOUR-SITE.com/wp-json/darban/v1"
r = requests.post(
    f"{base}/otp/send",
    headers={
        "Content-Type": "application/json",
        "X-Darban-Key": "YOUR_API_KEY",
        "User-Agent": "MyApp/1.0",
    },
    json={"phone": "09121234567", "dial_code": "98"},
    timeout=30,
)
print(r.json())
import 'dart:convert';
import 'package:http/http.dart' as http;

final uri = Uri.parse('https://YOUR-SITE.com/wp-json/darban/v1/otp/send');
final res = await http.post(
  uri,
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
    'User-Agent': 'MyApp/1.0',
  },
  body: jsonEncode({'phone': '09121234567', 'dial_code': '98'}),
);
print(jsonDecode(res.body));

POST /otp/verify

curl -X POST "https://YOUR-SITE.com/wp-json/darban/v1/otp/verify" \
  -H "Content-Type: application/json" \
  -H "X-Darban-Key: YOUR_API_KEY" \
  -d "{\"phone\":\"09121234567\",\"dial_code\":\"98\",\"code\":\"12345\"}"
const res = await fetch(`${base}/otp/verify`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: JSON.stringify({
    phone: '09121234567',
    dial_code: '98',
    code: '12345',
  }),
});
const data = await res.json();

if (data.code === 'login_success') {
  localStorage.setItem('access', data.session_data.jwt_token);
  localStorage.setItem('refresh', data.session_data.refresh_token);
}
<?php
$body = json_encode([
    'phone' => '09121234567',
    'dial_code' => '98',
    'code' => '12345',
]);

$ch = curl_init($base . '/otp/verify');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-Darban-Key: YOUR_API_KEY',
    ],
    CURLOPT_POSTFIELDS => $body,
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);
r = requests.post(
    f"{base}/otp/verify",
    headers={
        "Content-Type": "application/json",
        "X-Darban-Key": "YOUR_API_KEY",
    },
    json={
        "phone": "09121234567",
        "dial_code": "98",
        "code": "12345",
    },
)
data = r.json()
access = data.get("session_data", {}).get("jwt_token")
final res = await http.post(
  Uri.parse('$base/otp/verify'),
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: jsonEncode({
    'phone': '09121234567',
    'dial_code': '98',
    'code': '12345',
  }),
);
final data = jsonDecode(res.body) as Map<String, dynamic>;

۶) سناریو: ثبت‌نام با OTP (شماره جدید)

  1. ارسال کد — معمولاً کاربر از قبل وجود ندارد
  2. تأیید کد — پاسخ تکمیل پروفایل به‌همراه ticket و فیلدهای لازم
  3. ثبت‌نام با POST /otp/register

POST /otp/register

curl -X POST "https://YOUR-SITE.com/wp-json/darban/v1/otp/register" \
  -H "Content-Type: application/json" \
  -H "X-Darban-Key: YOUR_API_KEY" \
  -d "{\"ticket\":\"TICKET_FROM_VERIFY\",\"fields\":{\"first_name\":\"Ali\",\"last_name\":\"Rezaei\",\"email\":\"ali@example.com\"}}"
const res = await fetch(`${base}/otp/register`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: JSON.stringify({
    ticket: ticketFromVerify,
    fields: {
      first_name: 'Ali',
      last_name: 'Rezaei',
      email: 'ali@example.com',
    },
    device_id: 'android-pixel-8',
    set_cookie: false,
  }),
});
const data = await res.json(); // code: register_success
<?php
$body = json_encode([
    'ticket' => $ticket,
    'fields' => [
        'first_name' => 'Ali',
        'last_name' => 'Rezaei',
        'email' => 'ali@example.com',
    ],
]);
// POST {$base}/otp/register with header X-Darban-Key
r = requests.post(
    f"{base}/otp/register",
    headers={
        "Content-Type": "application/json",
        "X-Darban-Key": "YOUR_API_KEY",
    },
    json={
        "ticket": ticket,
        "fields": {
            "first_name": "Ali",
            "last_name": "Rezaei",
            "email": "ali@example.com",
        },
    },
)
print(r.json())
final res = await http.post(
  Uri.parse('$base/otp/register'),
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: jsonEncode({
    'ticket': ticket,
    'fields': {
      'first_name': 'Ali',
      'last_name': 'Rezaei',
      'email': 'ali@example.com',
    },
  }),
);
فرم‌ساز و API فیلدهای داخل fields باید با فیلدهای بخش «فرم‌ساز» منوی دربان یکی باشند. اگر فرم خالی باشد، عضویت فقط با موبایل انجام می‌شود.

۷) سناریو: ورود با رمز عبور

ورود با رمز باید در تنظیمات دربان فعال باشد. شناسه می‌تواند موبایل، ایمیل یا نام کاربری باشد.

POST /login

curl -X POST "https://YOUR-SITE.com/wp-json/darban/v1/login" \
  -H "Content-Type: application/json" \
  -H "X-Darban-Key: YOUR_API_KEY" \
  -d "{\"identifier\":\"09121234567\",\"password\":\"SecretPass123\",\"dial_code\":\"98\"}"
const res = await fetch(`${base}/login`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: JSON.stringify({
    identifier: '09121234567',
    password: 'SecretPass123',
    dial_code: '98',
  }),
});
const data = await res.json();

if (data.code === 'requires_mobile') {
  // حساب رمز دارد ولی موبایل تأیید نشده
  // ticket را نگه دارید و مسیر تأیید موبایل را ادامه دهید
}
<?php
$body = json_encode([
    'identifier' => '09121234567',
    'password' => 'SecretPass123',
    'dial_code' => '98',
]);
// POST {$base}/login
r = requests.post(
    f"{base}/login",
    headers={
        "Content-Type": "application/json",
        "X-Darban-Key": "YOUR_API_KEY",
    },
    json={
        "identifier": "09121234567",
        "password": "SecretPass123",
        "dial_code": "98",
    },
)
print(r.json())
final res = await http.post(
  Uri.parse('$base/login'),
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: jsonEncode({
    'identifier': '09121234567',
    'password': 'SecretPass123',
    'dial_code': '98',
  }),
);

۸) تازه‌سازی و خروج

POST /token/refresh

curl -X POST "https://YOUR-SITE.com/wp-json/darban/v1/token/refresh" \
  -H "Content-Type: application/json" \
  -H "X-Darban-Key: YOUR_API_KEY" \
  -d "{\"refresh_token\":\"REFRESH_JWT\"}"
const res = await fetch(`${base}/token/refresh`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: JSON.stringify({
    refresh_token: localStorage.getItem('refresh'),
  }),
});
const data = await res.json(); // code: token_refreshed
localStorage.setItem('access', data.session_data.jwt_token);
localStorage.setItem('refresh', data.session_data.refresh_token);
<?php
$body = json_encode(['refresh_token' => $refreshJwt]);
// POST {$base}/token/refresh
r = requests.post(
    f"{base}/token/refresh",
    headers={
        "Content-Type": "application/json",
        "X-Darban-Key": "YOUR_API_KEY",
    },
    json={"refresh_token": refresh_jwt},
)
print(r.json())
final res = await http.post(
  Uri.parse('$base/token/refresh'),
  headers: {
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: jsonEncode({'refresh_token': refreshJwt}),
);

POST /logout

curl -X POST "https://YOUR-SITE.com/wp-json/darban/v1/logout" \
  -H "Authorization: Bearer ACCESS_JWT" \
  -H "X-Darban-Key: YOUR_API_KEY"
await fetch(`${base}/logout`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${localStorage.getItem('access')}`,
    'X-Darban-Key': 'YOUR_API_KEY',
  },
});
localStorage.removeItem('access');
localStorage.removeItem('refresh');
<?php
$ch = curl_init($base . '/logout');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $accessJwt,
        'X-Darban-Key: YOUR_API_KEY',
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);
requests.post(
    f"{base}/logout",
    headers={
        "Authorization": f"Bearer {access_jwt}",
        "X-Darban-Key": "YOUR_API_KEY",
    },
)
await http.post(
  Uri.parse('$base/logout'),
  headers: {
    'Authorization': 'Bearer $accessJwt',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
);

۹) پروفایل

GET /profile

curl -X GET "https://YOUR-SITE.com/wp-json/darban/v1/profile" \
  -H "Authorization: Bearer ACCESS_JWT" \
  -H "X-Darban-Key: YOUR_API_KEY"
const res = await fetch(`${base}/profile`, {
  headers: {
    Authorization: `Bearer ${access}`,
    'X-Darban-Key': 'YOUR_API_KEY',
  },
});
const data = await res.json(); // code: profile
<?php
$ch = curl_init($base . '/profile');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $accessJwt,
        'X-Darban-Key: YOUR_API_KEY',
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($ch);
r = requests.get(
    f"{base}/profile",
    headers={
        "Authorization": f"Bearer {access_jwt}",
        "X-Darban-Key": "YOUR_API_KEY",
    },
)
print(r.json())
final res = await http.get(
  Uri.parse('$base/profile'),
  headers: {
    'Authorization': 'Bearer $accessJwt',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
);
print(res.body);

POST /profile/update

curl -X POST "https://YOUR-SITE.com/wp-json/darban/v1/profile/update" \
  -H "Authorization: Bearer ACCESS_JWT" \
  -H "Content-Type: application/json" \
  -H "X-Darban-Key: YOUR_API_KEY" \
  -d "{\"fields\":{\"first_name\":\"Ali\",\"last_name\":\"Rezaei\",\"display_name\":\"Ali R\",\"user_email\":\"ali@example.com\"}}"
await fetch(`${base}/profile/update`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${access}`,
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: JSON.stringify({
    fields: {
      first_name: 'Ali',
      last_name: 'Rezaei',
      display_name: 'Ali R',
      user_email: 'ali@example.com',
    },
  }),
});
<?php
$body = json_encode([
    'fields' => [
        'first_name' => 'Ali',
        'last_name' => 'Rezaei',
        'display_name' => 'Ali R',
        'user_email' => 'ali@example.com',
    ],
]);
// POST {$base}/profile/update + Bearer
requests.post(
    f"{base}/profile/update",
    headers={
        "Authorization": f"Bearer {access_jwt}",
        "Content-Type": "application/json",
        "X-Darban-Key": "YOUR_API_KEY",
    },
    json={
        "fields": {
            "first_name": "Ali",
            "last_name": "Rezaei",
            "display_name": "Ali R",
            "user_email": "ali@example.com",
        }
    },
)
await http.post(
  Uri.parse('$base/profile/update'),
  headers: {
    'Authorization': 'Bearer $accessJwt',
    'Content-Type': 'application/json',
    'X-Darban-Key': 'YOUR_API_KEY',
  },
  body: jsonEncode({
    'fields': {
      'first_name': 'Ali',
      'last_name': 'Rezaei',
      'display_name': 'Ali R',
      'user_email': 'ali@example.com',
    },
  }),
);

۱۰) نمونه ساخت امضای HMAC

import crypto from 'crypto'; // Node.js

const secret = process.env.DARBAN_API_SECRET;
const body = JSON.stringify({ phone: '09121234567', dial_code: '98' });
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto
  .createHmac('sha256', secret)
  .update(`${timestamp}.${body}`)
  .digest('hex');

// headers:
// X-Darban-Timestamp: timestamp
// X-Darban-Signature: signature
// X-Darban-Key: YOUR_API_KEY
<?php
$secret = getenv('DARBAN_API_SECRET');
$body = json_encode(['phone' => '09121234567', 'dial_code' => '98']);
$timestamp = (string) time();
$signature = hash_hmac('sha256', $timestamp . '.' . $body, $secret);
import hmac, hashlib, json, time, os

secret = os.environ["DARBAN_API_SECRET"].encode()
body = json.dumps({"phone": "09121234567", "dial_code": "98"}, separators=(",", ":"))
timestamp = str(int(time.time()))
signature = hmac.new(secret, f"{timestamp}.{body}".encode(), hashlib.sha256).hexdigest()
import 'dart:convert';
import 'package:crypto/crypto.dart';

final secret = utf8.encode(apiSecret);
final body = jsonEncode({'phone': '09121234567', 'dial_code': '98'});
final timestamp = (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString();
final signature = Hmac(sha256, secret)
    .convert(utf8.encode('$timestamp.$body'))
    .toString();

۱۱) کدهای خطای رایج

code معنی
phone_requiredشماره ارسال نشده
invalid_phone / blockedشماره نامعتبر یا مسدود
mismatch / expired / too_manyخطای تأیید کد
ticket_invalidتیکت منقضی یا استفاده‌شده
key_invalid / signature_invalidکلید یا امضا اشتباه
rate_limitedسقف درخواست در دقیقه پر شده
refresh_invalid / refresh_revokedتوکن تازه‌سازی نامعتبر
forbidden_roleنقش کاربر مجاز نیست
phone_in_useشماره متعلق به کاربر دیگر است
توجه درباره IP تشخیص IP از آدرس مستقیم سرور است. اگر پشت CDN هستید، فهرست IP را با دقت تنظیم کنید.

۱۲) چک‌لیست اتصال اپ

  • API در پنل فعال است و Base URL درست است
  • درگاه پیامک تست شده و کد واقعی می‌رسد
  • فرم‌ساز با فیلدهای اپ هماهنگ است
  • کلید API و کلید مخفی فقط در جای امن نگه‌داری می‌شوند
  • توکن دسترسی و تازه‌سازی جدا ذخیره می‌شوند و روی خطای احراز، refresh اجرا می‌شود
  • بعد از logout، توکن‌ها سمت اپ پاک می‌شوند