NAV
cURL PHP Node.js Go Python C#

مقدمه

به API درگاه پرداخت ایران‌درگاه خوش آمدید! این API با استاندارد snake_case برای تمامی فیلدهای ورودی و خروجی، امکان ایجاد تراکنش‌های پرداخت آنلاین و تأیید آن‌ها را فراهم می‌کند.

شما می‌توانید از نمونه کدهای موجود در سمت چپ صفحه استفاده کنید. کدهای نمونه در زبان‌های مختلف برنامه‌نویسی ارائه شده‌اند!

ویژگی‌های جدید

احراز هویت

ایران درگاه برای احراز هویت از یک توکن واحد استفاده می‌کند که برای ترمینال شما صادر و در اختیار شما قرار می‌گیرد.

فرمت توکن

توکن‌ها با پیشوندِ بامعنی صادر می‌شوند تا محیط عملیاتی و آزمایشی از روی نگاه قابل تشخیص باشند:

پیشوند محیط
idg_live_... محیط عملیاتی (Production)
idg_test_... محیط آزمایشی (Sandbox)

پس از صدور، توکن شکل کلی idg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx دارد (حدود ۵۰ کاراکتر).

ارسال توکن

توکن را به‌صورت مستقیم در هدر Authorization با پیشوند Bearer بفرستید:

curl "https://ipg.irandargah.com/v2/payments" \
  -H "Authorization: Bearer idg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
<?php
$headers = [
    'Authorization: Bearer idg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    'Content-Type: application/json',
];
const headers = {
  Authorization: "Bearer idg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "Content-Type": "application/json",
};
req.Header.Set("Authorization", "Bearer idg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx")
req.Header.Set("Content-Type", "application/json")
headers = {
    'Authorization': 'Bearer idg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    'Content-Type':  'application/json',
}
client.DefaultRequestHeaders.Add("Authorization", "Bearer idg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx");

دریافت توکن

صدور و چرخش توکن فقط پس از فعال شدن درگاه انجام می‌شود. برای دریافت توکن جدید:

  1. وارد پنل کاربری شوید
  2. به بخش «درگاه‌ها» بروید
  3. در صورت نیاز به توکن جدید، با پشتیبانی تماس بگیرید — توکن یک‌بار در پیام پاسخ ارسال می‌شود

چرخش توکن (Rotation)

زمانی که توکن چرخش پیدا می‌کند (rotation)، توکن قبلی به‌صورت خودکار به‌ مدت ۲۴ ساعت همچنان معتبر می‌ماند. این پنجره برای انتقال آرام بدون قطعی طراحی شده است:

لحظه حالت
T + 0 توکن جدید صادر می‌شود؛ توکن قدیمی هنوز معتبر است
T + [0, 24h) هر دو توکن کار می‌کنند؛ زمان مناسب برای انتقال تدریجی
T + 24h توکن قدیمی به‌طور کامل باطل می‌شود — فقط توکن جدید کار می‌کند

در طول این ۲۴ ساعت، هر درخواستی که با توکن قدیمی ارسال شود، در پاسخ خود این هدرهای هشدار را دریافت می‌کند:

هدر توضیح
X-Token-Deprecated مقدار true — یعنی این توکن در حال انقضاست
X-Token-Deprecated-Expires-At زمان دقیق انقضای توکن قدیمی (ISO 8601)

اگر در سرور خود این هدرها را رصد کنید، می‌توانید پیش از انقضا متوجه شوید کدام instance هنوز به توکن قدیمی متصل است.

ابطال اضطراری (Emergency Revoke)

اگر مشکوک شدید توکن لو رفته (مثلاً در گیت‌هاب کامیت کرده‌اید یا در گفتگوی تلگرام دیده شده):

  1. وارد پنل کاربری شوید
  2. ترمینال موردنظر را باز کنید ← دکمه‌ی «مدیریت کلید امضا»
  3. در پایین صفحه، بخش قرمز «ناحیه‌ی خطر» ← دکمه‌ی «باطل کن — توکن لو رفته» را بزنید

پس از ابطال، با پشتیبانی تماس بگیرید تا توکن جدید برایتان صادر شود.

کلید Idempotency

دریافت کلید Idempotency

curl -X GET "https://ipg.irandargah.com/v2/idempotency-key"
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/idempotency-key");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
$idempotencyKey = $result['idempotency_key'];
?>
fetch("https://ipg.irandargah.com/v2/idempotency-key")
  .then((response) => response.json())
  .then((data) => {
    const idempotencyKey = data.idempotency_key;
    console.log("Idempotency Key:", idempotencyKey);
  });
resp, err := http.Get("https://ipg.irandargah.com/v2/idempotency-key")
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
idempotencyKey := result["idempotency_key"].(string)
import requests

response = requests.get('https://ipg.irandargah.com/v2/idempotency-key')
data = response.json()
idempotency_key = data['idempotency_key']
using var client = new HttpClient();
var response = await client.GetAsync("https://ipg.irandargah.com/v2/idempotency-key");
var json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<dynamic>(json);
string idempotencyKey = result.idempotency_key;

پاسخ موفق:

{
  "success": true,
  "idempotency_key": "txn_1a2b3c4d5e6f7g8h9i0j",
  "expires_in": 86400,
  "usage": "Include this key in the Idempotency-Key header for your payment request"
}

این آدرس برای دریافت یک کلید منحصر به فرد Idempotency استفاده می‌شود که برای جلوگیری از تراکنش‌های تکراری ضروری است.

آدرس درخواست

GET
https://ipg.irandargah.com/v2/idempotency-key

پارامترهای پاسخ

پارامتر نوع توضیح
success boolean وضعیت موفقیت درخواست
idempotency_key string کلید منحصر به فرد با پیشوند txn_
expires_in integer مدت زمان اعتبار کلید به ثانیه (۸۶۴۰۰ = ۲۴ ساعت)
usage string راهنمای استفاده از کلید

فرآیند پرداخت

فرآیند پرداخت در ایران‌درگاه شامل مراحل زیر است:

  1. ایجاد تراکنش: درخواست پرداخت به آدرس /v2/payments ارسال می‌شود
  2. هدایت کاربر: کاربر با استفاده از authority دریافتی به صفحه پرداخت هدایت می‌شود
  3. پرداخت: کاربر عملیات پرداخت را در صفحه بانک انجام می‌دهد
  4. بازگشت: کاربر به callback_url شما برگردانده می‌شود
  5. تأیید: درخواست تأیید به آدرس /v2/verifications ارسال می‌شود

پرداخت

ایجاد تراکنش پرداخت

curl -X POST "https://ipg.irandargah.com/v2/payments" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-key-123" \
  -d '{
    "amount": 100000,
    "order_id": "ORDER-12345",
    "callback_url": "https://merchant.com/callback",
    "description": "خرید محصول آزمایشی",
    "mobile": "09123456789"
  }'
<?php
$data = [
    'amount' => 100000,
    'order_id' => 'ORDER-12345',
    'callback_url' => 'https://merchant.com/callback',
    'description' => 'خرید محصول آزمایشی',
    'mobile' => '09123456789'
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/payments");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer YOUR_API_TOKEN",
    "Content-Type: application/json",
    "Idempotency-Key: unique-key-123"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$result = json_decode($response, true);
?>
const payment = {
  amount: 100000,
  order_id: "ORDER-12345",
  callback_url: "https://merchant.com/callback",
  description: "خرید محصول آزمایشی",
  mobile: "09123456789",
};

const response = await fetch("https://ipg.irandargah.com/v2/payments", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
    "Idempotency-Key": "unique-key-123",
  },
  body: JSON.stringify(payment),
});

const data = await response.json();
console.log(data);
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

type PaymentRequest struct {
    Amount      int    `json:"amount"`
    OrderID     string `json:"order_id"`
    CallbackURL string `json:"callback_url"`
    Description string `json:"description"`
    Mobile      string `json:"mobile"`
}

func main() {
    payment := PaymentRequest{
        Amount:      100000,
        OrderID:     "ORDER-12345",
        CallbackURL: "https://merchant.com/callback",
        Description: "خرید محصول آزمایشی",
        Mobile:      "09123456789",
    }

    jsonData, _ := json.Marshal(payment)

    req, _ := http.NewRequest("POST", "https://ipg.irandargah.com/v2/payments", bytes.NewBuffer(jsonData))
    req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Idempotency-Key", "unique-key-123")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()
}
import requests
import json

payment_data = {
    'amount': 100000,
    'order_id': 'ORDER-12345',
    'callback_url': 'https://merchant.com/callback',
    'description': 'خرید محصول آزمایشی',
    'mobile': '09123456789'
}

headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json',
    'Idempotency-Key': 'unique-key-123'
}

response = requests.post(
    'https://ipg.irandargah.com/v2/payments',
    headers=headers,
    json=payment_data
)

result = response.json()
print(result)
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

public class PaymentRequest
{
    [JsonProperty("amount")]
    public int Amount { get; set; }

    [JsonProperty("order_id")]
    public string OrderId { get; set; }

    [JsonProperty("callback_url")]
    public string CallbackUrl { get; set; }

    [JsonProperty("description")]
    public string Description { get; set; }

    [JsonProperty("mobile")]
    public string Mobile { get; set; }
}

public async Task<string> CreatePaymentAsync()
{
    var payment = new PaymentRequest
    {
        Amount = 100000,
        OrderId = "ORDER-12345",
        CallbackUrl = "https://merchant.com/callback",
        Description = "خرید محصول آزمایشی",
        Mobile = "09123456789"
    };

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");
    client.DefaultRequestHeaders.Add("Idempotency-Key", "unique-key-123");

    var json = JsonConvert.SerializeObject(payment);
    var content = new StringContent(json, Encoding.UTF8, "application/json");

    var response = await client.PostAsync("https://ipg.irandargah.com/v2/payments", content);
    return await response.Content.ReadAsStringAsync();
}

پاسخ موفق:

{
  "success": true,
  "data": {
    "transaction": {
      "authority": "2025100121424146HC",
      "gateway_url": "https://ipg.irandargah.com/startpay/2025100121424146HC",
      "expires_at": "1404-06-28 10:50:00"
    },
    "meta": {
      "idempotency_key": "unique-key-123",
      "request_id": "65a4c7e8f1234",
      "processing_time_ms": 45
    }
  },
  "message": "تراکنش با موفقیت ایجاد شد",
  "status_code": 100,
  "timestamp": "1404-06-28 10:30:00"
}

پاسخ ناموفق (خطای اعتبارسنجی ورودی — HTTP 422):

{
  "success": false,
  "error": {
    "message": "خطا در اعتبارسنجی ورودی",
    "code": -2,
    "type": "validation_error",
    "details": {
      "validation": {
        "amount": ["حداقل مبلغ رعایت نشده است"],
        "order_id": ["شماره سفارش الزامی است"]
      }
    }
  },
  "status_code": -2,
  "timestamp": "1404-06-28 10:30:00",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

این آدرس برای ایجاد یک تراکنش پرداخت جدید استفاده می‌شود.

آدرس درخواست

POST
https://ipg.irandargah.com/v2/payments

هدرهای ارسالی

هدر مقدار توضیحات
Authorization Bearer YOUR_API_TOKEN توکن شما (اجباری)
Content-Type application/json نوع محتوای درخواست (اجباری)
Idempotency-Key unique-string کلید منحصر به فرد برای جلوگیری از درخواست‌های تکراری (اجباری)

پارامترهای ارسالی (snake_case)

پارامتر نوع اجباری توضیح
amount integer مبلغ تراکنش به ریال — حداقل ۱۰۰٬۰۰۰ (۱۰٬۰۰۰ تومان) و حداکثر ۴٬۰۰۰٬۰۰۰٬۰۰۰ (۴۰۰ میلیون تومان)
order_id string شناسه سفارش در سیستم شما — حداکثر ۵۰ کاراکتر، فقط A-Z, a-z, 0-9, -, _ (بدون فاصله یا فارسی)
callback_url string آدرس بازگشت پس از پرداخت — حداکثر ۵۰۰ کاراکتر، باید با http:// یا https:// شروع شود
mobile string شماره موبایل خریدار — فرمت‌های پذیرفته‌شده: 09xxxxxxxxx, 989xxxxxxxxx, +989xxxxxxxxx, 00989xxxxxxxxx, 9xxxxxxxxx
description string توضیحات تراکنش — حداکثر ۲۵۵ کاراکتر، بدون کاراکترهای < و > (جلوگیری از HTML)
card_number string شماره کارت پیش‌فرض — فرمت‌ها: کامل (۱۶ رقم) یا ماسک‌شده (۶ رقم + ****** + ۴ رقم). در صورت ارسال، خریدار فقط با این کارت می‌تواند پرداخت کند
action string متد HTTP برای فراخوانی callback — POST یا GET (پیش‌فرض: POST)
affiliate_code string کد معرف — ۴ تا ۶ کاراکتر، فقط حروف انگلیسی و اعداد
direct_verify boolean تأیید خودکار تراکنش بدون فراخوانی API تأیید (پیش‌فرض: false). در حالت true، callback با status_code=100 به‌جای 201 ارسال می‌شود

دریافت اطلاعات پرداخت

curl "https://ipg.irandargah.com/v2/payments/2025100121424146HC" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$authority = '2025100121424146HC';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/payments/{$authority}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_TOKEN"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const authority = "2025100121424146HC";

const response = await fetch(
  `https://ipg.irandargah.com/v2/payments/${authority}`,
  {
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  }
);

const data = await response.json();
authority := "2025100121424146HC"
url := fmt.Sprintf("https://ipg.irandargah.com/v2/payments/%s", authority)

req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")

client := &http.Client{}
resp, err := client.Do(req)
authority = '2025100121424146HC'

response = requests.get(
    f'https://ipg.irandargah.com/v2/payments/{authority}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)

result = response.json()
string authority = "2025100121424146HC";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var response = await client.GetAsync($"https://ipg.irandargah.com/v2/payments/{authority}");
var content = await response.Content.ReadAsStringAsync();

پاسخ موفق:

{
  "success": true,
  "data": {
    "transaction": {
      "authority": "2025100121424146HC",
      "ref_id": "2025100121424146HC",
      "amount": 100000,
      "status": "completed",
      "created_at": "1404-06-28 10:30:00",
      "updated_at": "1404-06-28 10:35:00"
    },
    "meta": {
      "request_id": "65a4c7e8f1234",
      "cached": false
    }
  },
  "message": "اطلاعات تراکنش با موفقیت دریافت شد",
  "status_code": 200,
  "timestamp": "1404-06-28 10:35:00"
}

پاسخ ناموفق (تراکنش یافت نشد — HTTP 404):

{
  "success": false,
  "error": {
    "message": "تراکنش یافت نشد",
    "code": 404,
    "type": "client_error",
    "details": {
      "transaction": ["تراکنش با این شناسه وجود ندارد"]
    }
  },
  "status_code": 404,
  "timestamp": "1404-06-28 10:35:00",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

این آدرس برای دریافت اطلاعات یک تراکنش پرداخت استفاده می‌شود.

آدرس درخواست

GET
https://ipg.irandargah.com/v2/payments/{authority}

پارامترهای ارسالی

پارامتر توضیح
authority شناسه یکتای تراکنش

فیلدهای پاسخ

فیلد نوع توضیح
authority string شناسه یکتای تراکنش
ref_id string شماره مرجع بانکی (در صورت تأیید موفق)
amount integer مبلغ تراکنش به ریال
status string وضعیت متنی — یکی از: pending, completed, failed, timeout, cancelled, unknown
created_at string زمان ایجاد به خورشیدی
updated_at string آخرین زمان به‌روزرسانی به خورشیدی

لغو پرداخت

curl -X POST "https://ipg.irandargah.com/v2/payments/2025100121424146HC/cancel" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$authority = '2025100121424146HC';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/payments/{$authority}/cancel");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_TOKEN"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const authority = "2025100121424146HC";

const response = await fetch(
  `https://ipg.irandargah.com/v2/payments/${authority}/cancel`,
  {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  }
);
authority := "2025100121424146HC"
url := fmt.Sprintf("https://ipg.irandargah.com/v2/payments/%s/cancel", authority)

req, _ := http.NewRequest("POST", url, nil)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")

client := &http.Client{}
resp, err := client.Do(req)
authority = '2025100121424146HC'

response = requests.post(
    f'https://ipg.irandargah.com/v2/payments/{authority}/cancel',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
string authority = "2025100121424146HC";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var response = await client.PostAsync($"https://ipg.irandargah.com/v2/payments/{authority}/cancel", null);

پاسخ موفق:

{
  "success": true,
  "data": {
    "transaction": {
      "authority": "2025100121424146HC",
      "ref_id": null,
      "amount": 100000,
      "status": "completed",
      "created_at": "1404-06-28 10:30:00",
      "updated_at": "1404-06-28 10:35:00"
    },
    "meta": {
      "request_id": "65a4c7e8f1234",
      "cached": false
    }
  },
  "message": "پرداخت با موفقیت لغو شد",
  "status_code": 200,
  "timestamp": "1404-06-28 10:35:00"
}

پاسخ ناموفق (تراکنش قابل لغو نیست — HTTP 400):

{
  "success": false,
  "error": {
    "message": "تراکنش قابل لغو نیست",
    "code": 400,
    "type": "client_error",
    "details": {
      "transaction": ["وضعیت تراکنش اجازه لغو را نمی‌دهد"]
    }
  },
  "status_code": 400,
  "timestamp": "1404-06-28 10:35:00",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

این آدرس برای لغو یک تراکنش پرداخت استفاده می‌شود.

آدرس درخواست

POST
https://ipg.irandargah.com/v2/payments/{authority}/cancel

پارامترهای ارسالی

پارامتر توضیح
authority شناسه یکتای تراکنش

بازگشت از درگاه (Callback)

پارامترهای Callback

پس از انجام پرداخت توسط کاربر در درگاه بانکی، بانک کاربر را به آدرس callback_url شما با پارامترهای زیر هدایت می‌کند:

پارامترهای بازگشتی (snake_case)

پارامتر نوع توضیح
authority string شناسه یکتای تراکنش
status_code integer کد وضعیت پرداخت (201 یا 100 = موفق، مقادیر منفی = ناموفق)
message string پیام توضیحی وضعیت
amount integer مبلغ پرداخت شده به ریال
order_id string شناسه سفارش شما
ref_id string شماره مرجع بانکی (در صورت موفقیت با direct_verify=true)
card_pan string شماره کارت ماسک شده (در صورت موفقیت با direct_verify=true)

نمونه آدرس Callback

فرمت بازگشت اطلاعات

https://yoursite.com/callback?
  authority=2025100121424146HC&
  status_code=201&
  message=پرداخت+در+انتظار+تایید+است&
  amount=100000&
  order_id=ORDER-12345&
  ref_id=123456789&
  card_pan=603799******1234

مثال پردازش Callback

<?php
// Laravel - V2 Callback Handler (snake_case)
Route::any('/callback', function (Request $request) {
    // دریافت پارامترهای callback - تمام فیلدها snake_case هستند
    $callbackData = [
        'authority'   => $request->input('authority'),
        'status_code' => (int) $request->input('status_code'),
        'message'     => $request->input('message'),
        'amount'      => (int) $request->input('amount'),
        'order_id'    => $request->input('order_id'),
        'ref_id'      => $request->input('ref_id'),
        'card_pan'    => $request->input('card_pan'),
    ];

    // بررسی وضعیت پرداخت
    // کد 201 = پرداخت موفق، منتظر تأیید (حالت معمول)
    // کد 100 = پرداخت و تأیید موفق (حالت direct_verify=true)
    if (in_array($callbackData['status_code'], [201, 100])) {
        // پرداخت موفق - تأیید با API (در حالت direct_verify=false)
        $response = Http::withToken(env('API_TOKEN'))
            ->post('https://ipg.irandargah.com/v2/verifications', [
                'authority' => $callbackData['authority'],
                'amount'    => $callbackData['amount'],
            ]);

        $result = $response->json();

        if ($result['success']) {
            $ref_id = $result['data']['verification']['ref_id'];

            // به‌روزرسانی وضعیت سفارش
            Order::where('order_id', $callbackData['order_id'])
                ->update([
                    'status'    => 'paid',
                    'ref_id'    => $ref_id,
                    'card_pan'  => $callbackData['card_pan'],
                ]);

            return view('payment.success', ['ref_id' => $ref_id]);
        }
    }

    // پرداخت ناموفق
    return view('payment.failed', [
        'status_code' => $callbackData['status_code']
    ]);
});
?>
// Node.js/Express - V2 Callback Handler (snake_case)
app.all("/callback", async (req, res) => {
  // پارامترها از body یا query string دریافت می‌شوند (بسته به action)
  const params = { ...req.query, ...req.body };
  const { authority, status_code, message, amount, order_id, ref_id, card_pan } = params;

  // کد 201 = موفق (منتظر تأیید)، کد 100 = موفق (تأیید شده)
  if (parseInt(status_code) === 201 || parseInt(status_code) === 100) {
    // Verify payment with API
    const response = await fetch(
      "https://ipg.irandargah.com/v2/verifications",
      {
        method: "POST",
        headers: {
          Authorization: "Bearer YOUR_API_TOKEN",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          authority,
          amount: parseInt(amount),
        }),
      }
    );

    const result = await response.json();

    if (result.success) {
      // Update order status in database
      await Order.update(
        {
          status:   "paid",
          ref_id:   result.data.verification.ref_id,
          card_pan: card_pan,
        },
        { where: { order_id } }
      );

      return res.render("success", {
        ref_id: result.data.verification.ref_id,
      });
    }
  }

  res.render("failed", { status_code });
});
# Python/Django - V2 Callback Handler (snake_case)
from django.shortcuts import render
import requests

def payment_callback(request):
    # دریافت پارامترهای callback (GET یا POST بسته به action)
    params = request.POST if request.method == 'POST' else request.GET
    callback_data = {
        'authority':   params.get('authority'),
        'status_code': int(params.get('status_code', -1)),
        'message':     params.get('message'),
        'amount':      int(params.get('amount', 0)),
        'order_id':    params.get('order_id'),
        'ref_id':      params.get('ref_id'),
        'card_pan':    params.get('card_pan'),
    }

    # کد 201 = موفق (منتظر تأیید)، کد 100 = موفق (تأیید شده)
    if callback_data['status_code'] in [201, 100]:
        # تأیید پرداخت با API
        response = requests.post(
            'https://ipg.irandargah.com/v2/verifications',
            headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
            json={
                'authority': callback_data['authority'],
                'amount':    callback_data['amount']
            }
        )

        result = response.json()

        if result['success']:
            # به‌روزرسانی سفارش
            Order.objects.filter(order_id=callback_data['order_id']).update(
                status='paid',
                ref_id=result['data']['verification']['ref_id'],
                card_pan=callback_data['card_pan']
            )

            return render(request, 'payment/success.html', {
                'ref_id': result['data']['verification']['ref_id']
            })

    return render(request, 'payment/failed.html', {
        'status_code': callback_data['status_code']
    })

کدهای وضعیت Callback

status_code معنی اقدام
201 پرداخت موفق، منتظر تأیید API فراخوانی API تأیید (/verifications)
100 پرداخت و تأیید موفق (direct_verify) ذخیره ref_id و نمایش موفقیت
-1 پرداخت ناموفق یا لغو توسط کاربر نمایش خطا به کاربر

تأیید پرداخت

تأیید تراکنش

curl -X POST "https://ipg.irandargah.com/v2/verifications" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: verification-key-123" \
  -d '{
    "authority": "2025100121424146HC",
    "amount": 100000
  }'
<?php
$data = [
    'authority' => '2025100121424146HC',
    'amount' => 100000
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/verifications");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer YOUR_API_TOKEN",
    "Content-Type: application/json",
    "Idempotency-Key: verification-key-123"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
?>
const verification = {
  authority: "2025100121424146HC",
  amount: 100000,
};

const response = await fetch("https://ipg.irandargah.com/v2/verifications", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
    "Idempotency-Key": "verification-key-123",
  },
  body: JSON.stringify(verification),
});

const data = await response.json();
type VerificationRequest struct {
    Authority string `json:"authority"`
    Amount    int    `json:"amount"`
}

func verifyPayment() {
    verification := VerificationRequest{
        Authority: "2025100121424146HC",
        Amount:    100000,
    }

    jsonData, _ := json.Marshal(verification)

    req, _ := http.NewRequest("POST", "https://ipg.irandargah.com/v2/verifications", bytes.NewBuffer(jsonData))
    req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Idempotency-Key", "verification-key-123")

    client := &http.Client{}
    resp, err := client.Do(req)
}
verification_data = {
    'authority': '2025100121424146HC',
    'amount': 100000
}

headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json',
    'Idempotency-Key': 'verification-key-123'
}

response = requests.post(
    'https://ipg.irandargah.com/v2/verifications',
    headers=headers,
    json=verification_data
)

result = response.json()
public class VerificationRequest
{
    [JsonProperty("authority")]
    public string Authority { get; set; }

    [JsonProperty("amount")]
    public int Amount { get; set; }
}

var verification = new VerificationRequest
{
    Authority = "2025100121424146HC",
    Amount = 100000
};

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");
client.DefaultRequestHeaders.Add("Idempotency-Key", "verification-key-123");

var json = JsonConvert.SerializeObject(verification);
var content = new StringContent(json, Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://ipg.irandargah.com/v2/verifications", content);

پاسخ موفق:

{
  "success": true,
  "data": {
    "verification": {
      "ref_id": "123456789",
      "authority": "2025100121424146HC",
      "amount": 100000,
      "verified_at": "1404-06-28 10:35:00"
    },
    "meta": {
      "request_id": "req_verify_001",
      "processing_time_ms": 85
    }
  },
  "message": "تراکنش با موفقیت تأیید شد",
  "status_code": 200,
  "timestamp": "1404-06-28 10:35:00"
}

پاسخ ناموفق (شناسه یا مبلغ نادرست — HTTP 400):

{
  "success": false,
  "error": {
    "message": "شناسه یکتا، شماره سفارش یا مبلغ اشتباه است",
    "code": -19,
    "type": "business_logic_error"
  },
  "status_code": -19,
  "timestamp": "1404-06-28 10:35:00",
  "meta": {
    "request_id": "req_verify_001"
  }
}

این آدرس پس از بازگشت کاربر از صفحه پرداخت برای تأیید نهایی تراکنش استفاده می‌شود.

آدرس درخواست

POST
https://ipg.irandargah.com/v2/verifications

پارامترهای ارسالی (snake_case)

پارامتر نوع الزامی توضیح
authority string شناسه یکتای تراکنش
amount integer مبلغ تراکنش به ریال (برای اعتبارسنجی)
order_id string شناسه سفارش (اختیاری)

وضعیت تأیید

curl "https://ipg.irandargah.com/v2/verifications/2025100121424146HC" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$authority = '2025100121424146HC';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/verifications/{$authority}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_TOKEN"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const authority = "2025100121424146HC";

const response = await fetch(
  `https://ipg.irandargah.com/v2/verifications/${authority}`,
  {
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  }
);

const data = await response.json();
authority := "2025100121424146HC"
url := fmt.Sprintf("https://ipg.irandargah.com/v2/verifications/%s", authority)

req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")

client := &http.Client{}
resp, err := client.Do(req)
authority = '2025100121424146HC'

response = requests.get(
    f'https://ipg.irandargah.com/v2/verifications/{authority}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)

result = response.json()
string authority = "2025100121424146HC";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var response = await client.GetAsync($"https://ipg.irandargah.com/v2/verifications/{authority}");
var content = await response.Content.ReadAsStringAsync();

پاسخ موفق:

{
  "success": true,
  "data": {
    "verification": {
      "ref_id": "123456789",
      "authority": "2025100121424146HC",
      "amount": 100000,
      "verified_at": "1404-06-28 10:35:00"
    },
    "meta": {
      "request_id": "req_status_001"
    }
  },
  "message": "اطلاعات تراکنش با موفقیت دریافت شد",
  "status_code": 200,
  "timestamp": "1404-06-28 10:40:00"
}

پاسخ ناموفق (تراکنش یافت نشد — HTTP 404):

{
  "success": false,
  "error": {
    "message": "تراکنش یافت نشد",
    "code": 404,
    "type": "client_error",
    "details": {
      "transaction": ["تراکنش با این شناسه وجود ندارد"]
    }
  },
  "status_code": 404,
  "timestamp": "1404-06-28 10:40:00",
  "meta": {
    "request_id": "req_status_001"
  }
}

این آدرس برای بررسی وضعیت تأیید یک تراکنش استفاده می‌شود.

آدرس درخواست

GET
https://ipg.irandargah.com/v2/verifications/{authority}

پارامترهای ارسالی

پارامتر توضیح
authority شناسه یکتای تراکنش

تلاش مجدد تأیید

curl -X POST "https://ipg.irandargah.com/v2/verifications/2025100121424146HC/retry" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$authority = '2025100121424146HC';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/verifications/{$authority}/retry");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_TOKEN"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const authority = "2025100121424146HC";

const response = await fetch(
  `https://ipg.irandargah.com/v2/verifications/${authority}/retry`,
  {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  }
);
authority := "2025100121424146HC"
url := fmt.Sprintf("https://ipg.irandargah.com/v2/verifications/%s/retry", authority)

req, _ := http.NewRequest("POST", url, nil)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")

client := &http.Client{}
resp, err := client.Do(req)
authority = '2025100121424146HC'

response = requests.post(
    f'https://ipg.irandargah.com/v2/verifications/{authority}/retry',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
string authority = "2025100121424146HC";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var response = await client.PostAsync($"https://ipg.irandargah.com/v2/verifications/{authority}/retry", null);

پاسخ موفق:

{
  "success": true,
  "data": {
    "verification": {
      "ref_id": "123456789",
      "authority": "2025100121424146HC",
      "amount": 100000,
      "verified_at": "1404-06-28 10:45:00"
    },
    "meta": {
      "request_id": "req_retry_001",
      "processing_time_ms": 120
    }
  },
  "message": "تأیید مجدد با موفقیت انجام شد",
  "status_code": 200,
  "timestamp": "1404-06-28 10:45:00"
}

پاسخ ناموفق (تراکنش یافت نشد — HTTP 404):

{
  "success": false,
  "error": {
    "message": "تراکنش یافت نشد",
    "code": 404,
    "type": "client_error",
    "details": {
      "transaction": ["تراکنش با این شناسه وجود ندارد"]
    }
  },
  "status_code": 404,
  "timestamp": "1404-06-28 10:45:00",
  "meta": {
    "request_id": "req_retry_001"
  }
}

این آدرس برای تلاش مجدد تأیید یک تراکنش ناموفق استفاده می‌شود.

آدرس درخواست

POST
https://ipg.irandargah.com/v2/verifications/{authority}/retry

پارامترهای ارسالی

پارامتر توضیح
authority شناسه یکتای تراکنش

تراکنش‌ها

فهرست تراکنش‌ها

curl "https://ipg.irandargah.com/v2/transactions?page=1&per_page=10&status=completed&from_date=1404-06-01&to_date=1404-06-31" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$query = http_build_query([
    'page'      => 1,
    'per_page'  => 10,
    'status'    => 'completed',
    'from_date' => '1404-06-01',
    'to_date'   => '1404-06-31',
]);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/transactions?{$query}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_TOKEN"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const params = new URLSearchParams({
  page:      1,
  per_page:  10,
  status:    "completed",
  from_date: "1404-06-01",
  to_date:   "1404-06-31",
});

const response = await fetch(
  `https://ipg.irandargah.com/v2/transactions?${params}`,
  {
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  }
);
params := url.Values{}
params.Add("page", "1")
params.Add("per_page", "10")
params.Add("status", "completed")
params.Add("from_date", "1404-06-01")
params.Add("to_date", "1404-06-31")

url := fmt.Sprintf("https://ipg.irandargah.com/v2/transactions?%s", params.Encode())

req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
params = {
    'page':      1,
    'per_page':  10,
    'status':    'completed',
    'from_date': '1404-06-01',
    'to_date':   '1404-06-31',
}

response = requests.get(
    'https://ipg.irandargah.com/v2/transactions',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    params=params
)
var query = "?page=1&per_page=10&status=completed&from_date=1404-06-01&to_date=1404-06-31";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var response = await client.GetAsync($"https://ipg.irandargah.com/v2/transactions{query}");

پاسخ موفق:

{
  "success": true,
  "data": {
    "transactions": [
      {
        "authority": "2025100121424146HC",
        "amount": 100000,
        "status": "completed",
        "order_id": "ORDER-12345",
        "ref_code": "2025100121424146HC",
        "created_at": "1404-06-28 10:30:00",
        "verified_at": "1404-06-28 10:45:00"
      }
    ],
    "pagination": {
      "current_page": 1,
      "per_page": 10,
      "total": 1,
      "last_page": 1
    }
  },
  "timestamp": "1404-06-28 10:45:00"
}

پاسخ ناموفق (توکن نامعتبر — HTTP 401):

{
  "success": false,
  "error": {
    "message": "اطلاعات احراز هویت نامعتبر است",
    "code": -51,
    "type": "authentication_error",
    "details": {
      "authentication": ["اطلاعات احراز هویت نامعتبر است"]
    }
  },
  "status_code": -51,
  "timestamp": "1404-06-28 10:45:00",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

این آدرس برای دریافت فهرست تراکنش‌ها استفاده می‌شود.

آدرس درخواست

GET
https://ipg.irandargah.com/v2/transactions

پارامترهای ارسالی

پارامتر اجباری پیش‌فرض توضیح
from_date تاریخ شروع به خورشیدی (YYYY-MM-DD) — نمی‌تواند تاریخ آینده باشد
to_date تاریخ پایان به خورشیدی (YYYY-MM-DD) — باید بزرگ‌تر یا مساوی from_date باشد
page 1 شماره صفحه
per_page 10 تعداد آیتم در هر صفحه (حداکثر 100)
status فیلتر بر اساس وضعیت — یکی از: pending, completed, failed, cancelled

جزئیات تراکنش

curl "https://ipg.irandargah.com/v2/transactions/2025100121424146HC" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$authority = '2025100121424146HC';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/transactions/{$authority}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_TOKEN"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const authority = "2025100121424146HC";

const response = await fetch(
  `https://ipg.irandargah.com/v2/transactions/${authority}`,
  {
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  }
);
authority := "2025100121424146HC"
url := fmt.Sprintf("https://ipg.irandargah.com/v2/transactions/%s", authority)

req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
authority = '2025100121424146HC'

response = requests.get(
    f'https://ipg.irandargah.com/v2/transactions/{authority}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
string authority = "2025100121424146HC";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var response = await client.GetAsync($"https://ipg.irandargah.com/v2/transactions/{authority}");

پاسخ موفق:

{
  "success": true,
  "data": {
    "transaction": {
      "authority": "2025100121424146HC",
      "order_id": "ORDER-12345",
      "amount": 100000,
      "status": "completed",
      "workflow_state": "COMPLETED",
      "description": "خرید محصول آزمایشی",
      "ref_code": "2025100121424146HC",
      "callback_url": "https://merchant.com/callback",
      "created_at": "1404-06-28 10:30:00",
      "updated_at": "1404-06-28 10:35:00",
      "expires_at": "1404-06-28 10:50:00",
      "is_expired": false,
      "can_be_verified": false,
      "verification_status": 200
    }
  },
  "timestamp": "1404-06-28 11:00:00"
}

پاسخ ناموفق (تراکنش یافت نشد — HTTP 404):

{
  "success": false,
  "error": {
    "message": "تراکنش یافت نشد",
    "code": 404,
    "type": "client_error",
    "details": {
      "transaction": ["تراکنش با این شناسه وجود ندارد"]
    }
  },
  "status_code": 404,
  "timestamp": "1404-06-28 11:00:00",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

این آدرس برای دریافت جزئیات کامل یک تراکنش استفاده می‌شود.

آدرس درخواست

GET
https://ipg.irandargah.com/v2/transactions/{authority}

پارامترهای ارسالی

پارامتر توضیح
authority شناسه یکتای تراکنش

فیلدهای پاسخ

فیلد نوع توضیح
authority string شناسه یکتای تراکنش
order_id string شناسه سفارش در سیستم شما
amount integer مبلغ تراکنش به ریال
status string وضعیت متنی — یکی از: pending, completed, failed, timeout, cancelled, unknown
workflow_state string وضعیت دقیق در ماشین حالت داخلی (برای دیباگ)
description string توضیحات تراکنش
ref_code string شماره مرجع بانکی (پس از تأیید موفق)
callback_url string آدرس callback ثبت‌شده برای این تراکنش
created_at string زمان ایجاد به خورشیدی
updated_at string آخرین زمان به‌روزرسانی به خورشیدی
expires_at string زمان انقضای تراکنش به خورشیدی
is_expired boolean آیا تراکنش منقضی شده است
can_be_verified boolean آیا تراکنش قابل تأیید است
verification_status integer کد وضعیت تأیید (۲۰۰ = تأییدشده)

وضعیت سیستم

بررسی سلامت

curl "https://ipg.irandargah.com/health"
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/health");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const response = await fetch("https://ipg.irandargah.com/health");
const data = await response.json();
resp, err := http.Get("https://ipg.irandargah.com/health")
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()
response = requests.get('https://ipg.irandargah.com/health')
result = response.json()
using var client = new HttpClient();
var response = await client.GetAsync("https://ipg.irandargah.com/health");
var content = await response.Content.ReadAsStringAsync();

پاسخ موفق:

{
  "status": "ok",
  "timestamp": "1404-06-29 10:30:00",
  "version": "2.0.0"
}

پاسخ ناسالم (یکی از سرویس‌های زیرساخت در دسترس نیست — HTTP 503):

{
  "status": "unhealthy",
  "timestamp": "1404-06-29 10:30:00",
  "version": "2.0.0"
}

این آدرس برای بررسی وضعیت سلامت API استفاده می‌شود.

آدرس درخواست

GET
https://ipg.irandargah.com/health

وب‌هوک‌ها

وب‌هوک‌ها به شما اجازه می‌دهند به‌جای polling، رویدادهای مهم (پرداخت موفق، استرداد، تسویه و …) را به‌صورت real-time روی URL خودتان دریافت کنید. ایران‌درگاه پس از وقوع هر رویداد، یک درخواست POST به آدرس ثبت‌شده‌ی شما ارسال می‌کند.

ثبت وب‌هوک

curl -X POST "https://ipg.irandargah.com/v2/webhooks/subscribe" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://merchant.com/webhook",
    "events": ["payment.completed", "payment.failed"],
    "secret": "your_optional_secret_min_8_chars",
    "description": "وب‌هوک اصلی فروشگاه"
  }'
<?php
$data = [
    'url'         => 'https://merchant.com/webhook',
    'events'      => ['payment.completed', 'payment.failed'],
    'secret'      => 'your_optional_secret_min_8_chars', // اختیاری
    'description' => 'وب‌هوک اصلی فروشگاه',              // اختیاری
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/webhooks/subscribe");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer YOUR_API_TOKEN",
    "Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const webhook = {
  url: "https://merchant.com/webhook",
  events: ["payment.completed", "payment.failed"],
  secret: "your_optional_secret_min_8_chars", // اختیاری
  description: "وب‌هوک اصلی فروشگاه", // اختیاری
};

const response = await fetch(
  "https://ipg.irandargah.com/v2/webhooks/subscribe",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
      "Content-Type": "application/json",
    },
    body: JSON.stringify(webhook),
  },
);
type WebhookSubscription struct {
    URL         string   `json:"url"`
    Events      []string `json:"events"`
    Secret      string   `json:"secret,omitempty"`
    Description string   `json:"description,omitempty"`
}

webhook := WebhookSubscription{
    URL:         "https://merchant.com/webhook",
    Events:      []string{"payment.completed", "payment.failed"},
    Secret:      "your_optional_secret_min_8_chars",
    Description: "وب‌هوک اصلی فروشگاه",
}

jsonData, _ := json.Marshal(webhook)

req, _ := http.NewRequest("POST", "https://ipg.irandargah.com/v2/webhooks/subscribe", bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("Content-Type", "application/json")
webhook_data = {
    'url':         'https://merchant.com/webhook',
    'events':      ['payment.completed', 'payment.failed'],
    'secret':      'your_optional_secret_min_8_chars',  # اختیاری
    'description': 'وب‌هوک اصلی فروشگاه',                # اختیاری
}

response = requests.post(
    'https://ipg.irandargah.com/v2/webhooks/subscribe',
    headers={
        'Authorization': 'Bearer YOUR_API_TOKEN',
        'Content-Type':  'application/json',
    },
    json=webhook_data
)
public class WebhookSubscription
{
    public string Url { get; set; }
    public List<string> Events { get; set; }
    public string Secret { get; set; }       // اختیاری
    public string Description { get; set; }  // اختیاری
}

var webhook = new WebhookSubscription
{
    Url         = "https://merchant.com/webhook",
    Events      = new List<string> { "payment.completed", "payment.failed" },
    Secret      = "your_optional_secret_min_8_chars",
    Description = "وب‌هوک اصلی فروشگاه",
};

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var json    = JsonConvert.SerializeObject(webhook);
var content = new StringContent(json, Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://ipg.irandargah.com/v2/webhooks/subscribe", content);

پاسخ موفق (HTTP 201):

{
  "success": true,
  "data": {
    "webhook": {
      "id": "65a4c7e8f1234",
      "url": "https://merchant.com/webhook",
      "events": ["payment.completed", "payment.failed"],
      "secret": "***masked***",
      "is_active": true,
      "created_at": "1404-06-29 10:30:00"
    }
  },
  "message": "Webhook subscription created successfully",
  "timestamp": "1404-06-29 10:30:00"
}

پاسخ ناموفق (خطای اعتبارسنجی — HTTP 422):

{
  "success": false,
  "error": {
    "message": "خطا در اعتبارسنجی ورودی",
    "code": -2,
    "type": "validation_error",
    "details": {
      "validation": {
        "url": ["The url field is required."],
        "events": ["The events field is required."]
      }
    }
  },
  "status_code": -2,
  "timestamp": "1404-06-29 10:30:00",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

آدرس درخواست

POST
https://ipg.irandargah.com/v2/webhooks/subscribe

پارامترهای ارسالی

پارامتر نوع اجباری توضیح
url string آدرس HTTPS endpoint شما (باید URL معتبر باشد)
events array حداقل یک رویداد از فهرست انواع رویدادها
secret string کلید مخفی برای امضای HMAC — بین ۸ تا ۶۴ کاراکتر. اگر ندهید، سرور یک کلید ۶۴ کاراکتری Hex تولید می‌کند
description string توضیح کوتاه برای شناسایی این وب‌هوک — حداکثر ۲۵۵ کاراکتر

انواع رویدادها

رویداد توضیح
payment.created تراکنش پرداخت جدید ایجاد شد
payment.completed پرداخت با موفقیت تکمیل شد
payment.failed پرداخت ناموفق بود
payment.cancelled پرداخت لغو شد
payment.reversed پرداخت معکوس/استرداد شد
verification.completed تأیید پرداخت با موفقیت انجام شد
verification.failed تأیید پرداخت ناموفق بود
refund.created درخواست برگشت وجه ثبت شد
refund.completed برگشت وجه با موفقیت تکمیل شد
settlement.created دسته تسویه‌حساب ایجاد شد
settlement.completed تسویه‌حساب با موفقیت انجام شد
settlement.failed تسویه‌حساب ناموفق بود

دریافت فهرست رویدادها

curl "https://ipg.irandargah.com/v2/webhooks/events" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/webhooks/events");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_TOKEN"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$events = json_decode($response, true)['data']['events'];
?>
const response = await fetch("https://ipg.irandargah.com/v2/webhooks/events", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});

const { data } = await response.json();
console.log(data.events);
req, _ := http.NewRequest("GET", "https://ipg.irandargah.com/v2/webhooks/events", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil { log.Fatal(err) }
defer resp.Body.Close()

var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
response = requests.get(
    'https://ipg.irandargah.com/v2/webhooks/events',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)

events = response.json()['data']['events']
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var response = await client.GetAsync("https://ipg.irandargah.com/v2/webhooks/events");
var content  = await response.Content.ReadAsStringAsync();

پاسخ موفق:

{
  "success": true,
  "data": {
    "events": {
      "payment.created": "Triggered when a new payment is initiated",
      "payment.completed": "Triggered when a payment is successfully completed",
      "...": "..."
    },
    "webhook_requirements": {
      "url": "Must be a valid HTTPS URL",
      "response_timeout": "10 seconds",
      "retry_attempts": "3 times with exponential backoff",
      "expected_response": "HTTP 200-299 status code",
      "signature_header": "X-Webhook-Signature (HMAC-SHA256)"
    }
  },
  "timestamp": "1404-06-29 10:30:00"
}
GET
https://ipg.irandargah.com/v2/webhooks/events

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

لغو اشتراک

curl -X POST "https://ipg.irandargah.com/v2/webhooks/unsubscribe" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"webhook_id": "65a4c7e8f1234"}'
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/webhooks/unsubscribe");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer YOUR_API_TOKEN",
    "Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['webhook_id' => '65a4c7e8f1234']));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const response = await fetch(
  "https://ipg.irandargah.com/v2/webhooks/unsubscribe",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ webhook_id: "65a4c7e8f1234" }),
  },
);
data := map[string]string{"webhook_id": "65a4c7e8f1234"}
jsonData, _ := json.Marshal(data)

req, _ := http.NewRequest("POST", "https://ipg.irandargah.com/v2/webhooks/unsubscribe", bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("Content-Type", "application/json")
response = requests.post(
    'https://ipg.irandargah.com/v2/webhooks/unsubscribe',
    headers={
        'Authorization': 'Bearer YOUR_API_TOKEN',
        'Content-Type':  'application/json',
    },
    json={'webhook_id': '65a4c7e8f1234'}
)
var data = new { webhook_id = "65a4c7e8f1234" };

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var json    = JsonConvert.SerializeObject(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://ipg.irandargah.com/v2/webhooks/unsubscribe", content);

پاسخ موفق:

{
  "success": true,
  "data": {
    "webhook_id": "65a4c7e8f1234",
    "status": "unsubscribed"
  },
  "message": "Webhook unsubscribed successfully",
  "timestamp": "1404-06-29 10:30:00"
}

پاسخ ناموفق (وب‌هوک یافت نشد — HTTP 404):

{
  "success": false,
  "error": {
    "message": "وب‌هوک یافت نشد",
    "code": 404,
    "type": "client_error",
    "details": {
      "webhook": ["اشتراک وب‌هوک با این شناسه وجود ندارد"]
    }
  },
  "status_code": 404,
  "timestamp": "1404-06-29 10:30:00",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

این آدرس وب‌هوک را غیرفعال می‌کند (is_active = false) — رکورد در دیتابیس باقی می‌ماند ولی دیگر رویدادی به این endpoint ارسال نمی‌شود.

POST
https://ipg.irandargah.com/v2/webhooks/unsubscribe

پارامترهای ارسالی

پارامتر نوع اجباری توضیح
webhook_id string شناسه‌ی وب‌هوک که در زمان ثبت دریافت کرده‌اید

تست وب‌هوک

curl -X POST "https://ipg.irandargah.com/v2/webhooks/test" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_id": "65a4c7e8f1234",
    "event_type": "payment.completed"
  }'
<?php
$data = [
    'webhook_id' => '65a4c7e8f1234',
    'event_type' => 'payment.completed',
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/webhooks/test");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer YOUR_API_TOKEN",
    "Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const response = await fetch("https://ipg.irandargah.com/v2/webhooks/test", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    webhook_id: "65a4c7e8f1234",
    event_type: "payment.completed",
  }),
});
data := map[string]string{
    "webhook_id": "65a4c7e8f1234",
    "event_type": "payment.completed",
}
jsonData, _ := json.Marshal(data)

req, _ := http.NewRequest("POST", "https://ipg.irandargah.com/v2/webhooks/test", bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("Content-Type", "application/json")
response = requests.post(
    'https://ipg.irandargah.com/v2/webhooks/test',
    headers={
        'Authorization': 'Bearer YOUR_API_TOKEN',
        'Content-Type':  'application/json',
    },
    json={
        'webhook_id': '65a4c7e8f1234',
        'event_type': 'payment.completed',
    }
)
var data = new {
    webhook_id = "65a4c7e8f1234",
    event_type = "payment.completed",
};

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var json    = JsonConvert.SerializeObject(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://ipg.irandargah.com/v2/webhooks/test", content);

پاسخ موفق:

{
  "success": true,
  "data": {
    "webhook_id": "65a4c7e8f1234",
    "event_type": "payment.completed",
    "test_result": {
      "status": "success",
      "response_code": 200,
      "response_time": null,
      "error": null
    }
  },
  "message": "Webhook test completed",
  "timestamp": "1404-06-29 10:30:00"
}

پاسخ ناموفق (وب‌هوک یافت نشد — HTTP 404):

{
  "success": false,
  "error": {
    "message": "وب‌هوک یافت نشد",
    "code": 404,
    "type": "client_error",
    "details": {
      "webhook": ["اشتراک وب‌هوک با این شناسه وجود ندارد"]
    }
  },
  "status_code": 404,
  "timestamp": "1404-06-29 10:30:00",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

این آدرس یک بدنه درخواست نمونه برای رویداد مشخص‌شده تولید کرده و فوراً به endpoint شما ارسال می‌کند تا بتوانید پیاده‌سازی خود را پیش از رفتن به محیط عملیاتی تست کنید.

POST
https://ipg.irandargah.com/v2/webhooks/test

پارامترهای ارسالی

پارامتر نوع اجباری توضیح
webhook_id string شناسه‌ی وب‌هوک
event_type string یکی از: payment.created, payment.completed, payment.failed, payment.cancelled, refund.created, refund.completed, verification.completed

ساختار پیام وب‌هوک

پیامی که به endpoint شما ارسال می‌شود ساختار زیر را دارد:

{
  "event": "payment.completed",
  "timestamp": "2025-10-01T10:35:00+03:30",
  "merchant_code": "MERCHANT001",
  "data": {
    "authority": "2025100121424146HC",
    "amount": 100000,
    "order_id": "ORDER-12345",
    "ref_code": "2025100121424146HC",
    "pan": "603799******1234",
    "verified_at": "1404-06-29 10:35:00"
  },
  "signature": "a1b2c3d4e5f6..."
}

فیلدهای ثابت بدنه درخواست

فیلد نوع توضیح
event string نوع رویداد (همان مقداری که در زمان اشتراک انتخاب کرده‌اید)
timestamp string زمان وقوع رویداد در فرمت ISO 8601 با منطقه زمانی تهران
merchant_code string کد پذیرنده‌ی شما
data object محتوای رویداد (فیلدها بسته به نوع رویداد متفاوت است — جدول زیر)
signature string امضای HMAC-SHA256 روی data (فقط اگر secret ست شده باشد)

فیلدهای data بر اساس نوع رویداد

رویداد فیلدهای داخل data
payment.created authority, amount, status, created_at
payment.completed / verification.completed authority, amount, order_id, ref_code, pan, verified_at
payment.failed / payment.cancelled / verification.failed authority, amount, status, message
refund.created refund_code, authority, amount, status, reason, created_at
refund.completed refund_code, authority, amount, status, completed_at
settlement.created / settlement.completed / settlement.failed settlement_code, amount, status, period

هدرهای وب‌هوک

هر درخواست وب‌هوک با هدرهای زیر ارسال می‌شود:

هدر توضیح
Content-Type همیشه application/json
User-Agent IranDargah-Webhook/1.0
X-Webhook-Event نوع رویداد (مثال: payment.completed)
X-Webhook-Timestamp زمان ارسال (Unix timestamp بر حسب ثانیه)
X-Webhook-ID شناسه یکتای این رویداد (برای deduplication و idempotency)
X-Webhook-Signature امضای HMAC-SHA256 — فقط اگر secret در زمان اشتراک ست شده باشد

راستی‌آزمایی امضا

<?php
function verifyWebhookSignature(string $rawBody, string $signature, string $secret): bool {
    // فقط فیلد data امضا می‌شود
    $payload  = json_decode($rawBody, true);
    $dataJson = json_encode($payload['data'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

    $expected = hash_hmac('sha256', $dataJson, $secret);
    return hash_equals($expected, $signature);
}

// استفاده
$body      = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

if (! verifyWebhookSignature($body, $signature, 'YOUR_WEBHOOK_SECRET')) {
    http_response_code(401);
    exit('Invalid signature');
}
?>
const crypto = require("crypto");

function verifyWebhookSignature(rawBody, signature, secret) {
  // فقط فیلد data امضا می‌شود
  const payload = JSON.parse(rawBody);
  const dataJson = JSON.stringify(payload.data);

  const expected = crypto
    .createHmac("sha256", secret)
    .update(dataJson)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

// در Express
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["x-webhook-signature"];
  if (!verifyWebhookSignature(req.body, signature, "YOUR_WEBHOOK_SECRET")) {
    return res.status(401).send("Invalid signature");
  }
  // ... پردازش webhook
  res.sendStatus(200);
});
import hmac, hashlib, json

def verify_webhook_signature(raw_body: bytes, signature: str, secret: str) -> bool:
    # فقط فیلد data امضا می‌شود
    payload   = json.loads(raw_body)
    data_json = json.dumps(payload['data'], ensure_ascii=False, separators=(',', ':'))

    expected = hmac.new(secret.encode(), data_json.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

Retry و Timeout

برای اطمینان از دریافت رویدادها، ایران‌درگاه ارسال ناموفق را با backoff نمایی تلاش مجدد می‌کند:

پارامتر مقدار
Timeout ۱۰ ثانیه (اگر endpoint شما در این بازه پاسخ ندهد، خطا تلقی می‌شود)
Retries حداکثر ۳ تلاش
Backoff exponential — ۲ دقیقه، ۴ دقیقه، ۸ دقیقه (سقف ۶۰ دقیقه)
موفقیت پاسخ HTTP با کد 2xx
شکست پاسخ غیر-2xx، timeout، یا عدم پاسخ‌دهی

پس از ۳ تلاش ناموفق، رویداد به DLQ (Dead Letter Queue) منتقل می‌شود و می‌توانید آن را از پنل مدیریتی مشاهده و در صورت نیاز دوباره retry کنید.

گزارش‌ها

گزارش روزانه

curl "https://ipg.irandargah.com/v2/reports/daily?date=1404-06-28" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$date = '1404-06-28';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/reports/daily?date={$date}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_TOKEN"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const date = "1404-06-28";

const response = await fetch(
  `https://ipg.irandargah.com/v2/reports/daily?date=${date}`,
  {
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  }
);
date := "1404-06-28"
url := fmt.Sprintf("https://ipg.irandargah.com/v2/reports/daily?date=%s", date)

req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
date = '1404-06-28'

response = requests.get(
    f'https://ipg.irandargah.com/v2/reports/daily?date={date}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
string date = "1404-06-28";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var response = await client.GetAsync($"https://ipg.irandargah.com/v2/reports/daily?date={date}");

پاسخ موفق:

{
  "success": true,
  "data": {
    "report_date": "1404-06-28",
    "summary": {
      "total_transactions": 150,
      "successful_transactions": 135,
      "failed_transactions": 15,
      "total_amount": 15000000,
      "successful_amount": 13500000,
      "success_rate": 90.0,
      "total_fees": 270000
    },
    "hourly_breakdown": [
      { "hour": 10, "transactions": 25, "amount": 2500000 }
    ],
    "payment_methods": [
      { "method": "card", "transactions": 140, "amount": 14000000 }
    ],
    "status_breakdown": [
      { "status": "completed", "count": 135 },
      { "status": "failed",    "count": 15  }
    ]
  },
  "timestamp": "1404-06-28 23:59:59"
}

پاسخ ناموفق (تاریخ نامعتبر — HTTP 422):

{
  "success": false,
  "error": {
    "message": "خطا در اعتبارسنجی ورودی",
    "code": -2,
    "type": "validation_error",
    "details": {
      "validation": {
        "date": ["The date must be a valid Jalali date format (Y-m-d)."]
      }
    }
  },
  "status_code": -2,
  "timestamp": "1404-06-28 23:59:59",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

این آدرس برای دریافت گزارش روزانه تراکنش‌ها استفاده می‌شود.

آدرس درخواست

GET
https://ipg.irandargah.com/v2/reports/daily

پارامترهای ارسالی

پارامتر الزامی توضیح
date تاریخ مورد نظر به خورشیدی (YYYY-MM-DD). در صورت ارسال نشدن، امروز درنظر گرفته می‌شود. نمی‌تواند تاریخ آینده باشد

فیلدهای پاسخ

فیلد نوع توضیح
report_date string تاریخ گزارش به خورشیدی
summary.total_transactions int تعداد کل تراکنش‌ها
summary.successful_transactions int تعداد تراکنش‌های موفق
summary.failed_transactions int تعداد تراکنش‌های ناموفق
summary.total_amount int جمع کل مبلغ تراکنش‌ها (ریال)
summary.successful_amount int جمع مبلغ تراکنش‌های موفق (ریال)
summary.success_rate float درصد موفقیت
summary.total_fees int جمع کارمزد (ریال)
hourly_breakdown array تفکیک ساعتی
payment_methods array تفکیک روش پرداخت
status_breakdown array تفکیک وضعیت

گزارش ماهانه

curl "https://ipg.irandargah.com/v2/reports/monthly?month=1404-06" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$month = '1404-06';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://ipg.irandargah.com/v2/reports/monthly?month={$month}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_TOKEN"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const month = "1404-06";

const response = await fetch(
  `https://ipg.irandargah.com/v2/reports/monthly?month=${month}`,
  {
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  }
);
month := "1404-06"
url := fmt.Sprintf("https://ipg.irandargah.com/v2/reports/monthly?month=%s", month)

req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
month = '1404-06'

response = requests.get(
    f'https://ipg.irandargah.com/v2/reports/monthly?month={month}',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
)
string month = "1404-06";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var response = await client.GetAsync($"https://ipg.irandargah.com/v2/reports/monthly?month={month}");

پاسخ موفق:

{
  "success": true,
  "data": {
    "report_month": "1404-06",
    "period": {
      "from": "1404-06-01",
      "to":   "1404-06-31"
    },
    "summary": {
      "total_transactions": 4500,
      "successful_transactions": 4050,
      "failed_transactions": 450,
      "total_amount": 450000000,
      "success_rate": 90.0
    },
    "daily_breakdown": [
      { "date": "1404-06-28", "transactions": 150, "amount": 15000000 }
    ],
    "payment_methods": [
      { "method": "card", "transactions": 4200, "amount": 420000000 }
    ],
    "psp_breakdown": [
      { "psp": "mellat",  "transactions": 2500, "amount": 250000000 },
      { "psp": "saderat", "transactions": 1550, "amount": 200000000 }
    ]
  },
  "timestamp": "1404-07-01 00:00:00"
}

پاسخ ناموفق (ماه نامعتبر — HTTP 422):

{
  "success": false,
  "error": {
    "message": "خطا در اعتبارسنجی ورودی",
    "code": -2,
    "type": "validation_error",
    "details": {
      "validation": {
        "month": ["The month must be a valid Jalali month format (Y-m)."]
      }
    }
  },
  "status_code": -2,
  "timestamp": "1404-07-01 00:00:00",
  "meta": {
    "request_id": "65a4c7e8f1234"
  }
}

آدرس درخواست

GET
https://ipg.irandargah.com/v2/reports/monthly

پارامترهای ارسالی

پارامتر الزامی توضیح
month ماه مورد نظر به خورشیدی (YYYY-MM). در صورت ارسال نشدن، ماه جاری درنظر گرفته می‌شود. نمی‌تواند ماه آینده باشد

فیلدهای پاسخ

فیلد نوع توضیح
report_month string ماه گزارش به خورشیدی
period.from / period.to string بازه‌ی تاریخی گزارش به خورشیدی
summary.* object خلاصه‌ی آماری (مشابه گزارش روزانه)
daily_breakdown array تفکیک روزانه
payment_methods array تفکیک روش پرداخت
psp_breakdown array تفکیک به‌ازای ارائه‌دهنده‌ی خدمات پرداخت (PSP)

محیط آزمایشی (Sandbox)

آدرس پایه محیط آزمایشی

https://sandbox.irandargah.com

محیط آزمایشی برای تست API اختیار شماست. این محیط دقیقاً مشابه محیط عملیاتی است با تفاوت‌های زیر:

تفاوت‌ها با محیط عملیاتی

ویژگی محیط عملیاتی محیط آزمایشی
آدرس پایه ipg.irandargah.com sandbox.irandargah.com
توکن احراز هویت توکن واقعی توکن تست (از پنل سندباکس)
تراکنش‌ها تراکنش واقعی با بانک تراکنش شبیه‌سازی شده
کارت‌های بانکی کارت‌های واقعی کارت‌های تستی (جدول زیر)
هزینه تراکنش کارمزد واقعی محاسبه می‌شود بدون هزینه

ساختار آدرس‌ها

محیط آزمایشی در زیردامنه جداگانه قرار دارد و ساختار کاملاً مشابه محیط عملیاتی دارد:

آدرس محیط عملیاتی محیط آزمایشی
آدرس پایه https://ipg.irandargah.com https://sandbox.irandargah.com
ایجاد تراکنش https://ipg.irandargah.com/v2/payments https://sandbox.irandargah.com/v2/payments
تائید تراکنش https://ipg.irandargah.com/v2/verifications https://sandbox.irandargah.com/v2/verifications

کارت‌های تستی

برای تست در محیط آزمایشی، از کارت‌های زیر استفاده کنید:

شماره کارت نتیجه CVV2 تاریخ انقضا توضیحات نوع خطا
6037997123456789 123 05/10 تراکنش موفق
6219861012345678 456 05/10 پرداخت ناموفق failed
5041721098765432 789 05/10 موجودی ناکافی insufficient
6273811122334455 321 05/10 انقضای زمان تراکنش timeout

نحوه استفاده

تمام آدرس‌های API بدون تغییر در محیط آزمایشی قابل استفاده هستند، فقط:

  1. آدرس پایه را تغییر دهید
  2. از توکن تست استفاده کنید
  3. از کارت‌های تستی استفاده کنید

مثال: ایجاد پرداخت در محیط آزمایشی

تنها تفاوت محیط آزمایشی با محیط عملیاتی در آدرس پایه و توکن است — همان درخواست و همان پاسخ. کافی است این دو را در زمان بیلد روی هر محیطی که می‌خواهید ست کنید:

# Production
BASE_URL="https://ipg.irandargah.com";       TOKEN="YOUR_PRODUCTION_TOKEN"
# یا Sandbox
BASE_URL="https://sandbox.irandargah.com";   TOKEN="YOUR_SANDBOX_TOKEN"

curl -X POST "$BASE_URL/v2/payments" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 100000,
    "order_id": "ORDER-12345",
    "callback_url": "https://yoursite.com/callback"
  }'
<?php
$environment = 'sandbox'; // 'production' یا 'sandbox'
$config = [
    'production' => [
        'base_url' => 'https://ipg.irandargah.com',
        'token'    => 'YOUR_PRODUCTION_TOKEN',
    ],
    'sandbox' => [
        'base_url' => 'https://sandbox.irandargah.com',
        'token'    => 'YOUR_SANDBOX_TOKEN',
    ],
];
$baseUrl = $config[$environment]['base_url'];
$token   = $config[$environment]['token'];

$paymentData = [
    'amount'       => 100000,
    'order_id'     => 'ORDER-' . time(),
    'callback_url' => 'https://yoursite.com/callback',
    'description'  => 'خرید تستی',
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "{$baseUrl}/v2/payments");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer {$token}",
    "Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($paymentData, JSON_UNESCAPED_UNICODE));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
if ($result['success']) {
    $gatewayUrl = $result['data']['transaction']['gateway_url'];
    header('Location: ' . $gatewayUrl);
}
?>
const environment = "sandbox"; // یا "production"
const config = {
  production: {
    base_url: "https://ipg.irandargah.com",
    token: "YOUR_PRODUCTION_TOKEN",
  },
  sandbox: {
    base_url: "https://sandbox.irandargah.com",
    token: "YOUR_SANDBOX_TOKEN",
  },
};
const { base_url, token } = config[environment];

const response = await fetch(`${base_url}/v2/payments`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: 100000,
    order_id: `ORDER-${Date.now()}`,
    callback_url: "https://yoursite.com/callback",
    description: "خرید تستی",
  }),
});

const result = await response.json();
if (result.success) {
  window.location.href = result.data.transaction.gateway_url;
}
type EnvConfig struct{ BaseURL, Token string }

config := map[string]EnvConfig{
    "production": {"https://ipg.irandargah.com",     "YOUR_PRODUCTION_TOKEN"},
    "sandbox":    {"https://sandbox.irandargah.com", "YOUR_SANDBOX_TOKEN"},
}
env := config["sandbox"] // یا "production"

payload, _ := json.Marshal(map[string]interface{}{
    "amount":       100000,
    "order_id":     fmt.Sprintf("ORDER-%d", time.Now().Unix()),
    "callback_url": "https://yoursite.com/callback",
})

req, _ := http.NewRequest("POST", env.BaseURL + "/v2/payments", bytes.NewBuffer(payload))
req.Header.Set("Authorization", "Bearer " + env.Token)
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
import requests, time

config = {
    'production': {'base_url': 'https://ipg.irandargah.com',     'token': 'YOUR_PRODUCTION_TOKEN'},
    'sandbox':    {'base_url': 'https://sandbox.irandargah.com', 'token': 'YOUR_SANDBOX_TOKEN'},
}
env = config['sandbox']  # یا 'production'

response = requests.post(
    f"{env['base_url']}/v2/payments",
    headers={
        'Authorization': f"Bearer {env['token']}",
        'Content-Type':  'application/json',
    },
    json={
        'amount':       100000,
        'order_id':     f"ORDER-{int(time.time())}",
        'callback_url': 'https://yoursite.com/callback',
        'description':  'خرید تستی',
    }
)

result = response.json()
if result['success']:
    gateway_url = result['data']['transaction']['gateway_url']
var config = new Dictionary<string, (string BaseUrl, string Token)> {
    ["production"] = ("https://ipg.irandargah.com",     "YOUR_PRODUCTION_TOKEN"),
    ["sandbox"]    = ("https://sandbox.irandargah.com", "YOUR_SANDBOX_TOKEN"),
};
var env = config["sandbox"]; // یا "production"

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {env.Token}");

var body = new {
    amount       = 100000,
    order_id     = $"ORDER-{DateTimeOffset.Now.ToUnixTimeSeconds()}",
    callback_url = "https://yoursite.com/callback",
    description  = "خرید تستی",
};
var content  = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
var response = await client.PostAsync($"{env.BaseUrl}/v2/payments", content);

مثال: تأیید پرداخت در محیط آزمایشی

BASE_URL="https://sandbox.irandargah.com"
TOKEN="YOUR_SANDBOX_TOKEN"

curl -X POST "$BASE_URL/v2/verifications" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "authority": "2025100121424146HC",
    "amount": 100000
  }'
<?php
$baseUrl = 'https://sandbox.irandargah.com';
$token   = 'YOUR_SANDBOX_TOKEN';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "{$baseUrl}/v2/verifications");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer {$token}",
    "Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'authority' => '2025100121424146HC',
    'amount'    => 100000,
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
?>
const baseUrl = "https://sandbox.irandargah.com";
const token = "YOUR_SANDBOX_TOKEN";

const response = await fetch(`${baseUrl}/v2/verifications`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    authority: "2025100121424146HC",
    amount: 100000,
  }),
});
baseURL := "https://sandbox.irandargah.com"
token   := "YOUR_SANDBOX_TOKEN"

payload, _ := json.Marshal(map[string]interface{}{
    "authority": "2025100121424146HC",
    "amount":    100000,
})

req, _ := http.NewRequest("POST", baseURL + "/v2/verifications", bytes.NewBuffer(payload))
req.Header.Set("Authorization", "Bearer " + token)
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
base_url = 'https://sandbox.irandargah.com'
token    = 'YOUR_SANDBOX_TOKEN'

response = requests.post(
    f'{base_url}/v2/verifications',
    headers={
        'Authorization': f'Bearer {token}',
        'Content-Type':  'application/json',
    },
    json={
        'authority': '2025100121424146HC',
        'amount':    100000,
    }
)
var baseUrl = "https://sandbox.irandargah.com";
var token   = "YOUR_SANDBOX_TOKEN";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");

var body    = new { authority = "2025100121424146HC", amount = 100000 };
var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
var response = await client.PostAsync($"{baseUrl}/v2/verifications", content);

دریافت توکن تست

برای دریافت توکن تست:

  1. به پنل مدیریت محیط آزمایشی مراجعه کنید: https://sandbox.irandargah.com/dashboard
  2. از بخش API Tokens یک توکن جدید ایجاد کنید
  3. توکن را در کدهای تست خود استفاده کنید

تست فرآیند کامل

1. ایجاد تراکنش

curl -X POST "https://sandbox.irandargah.com/v2/payments" \
  -H "Authorization: Bearer YOUR_SANDBOX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 100000,
    "order_id": "TEST-001",
    "callback_url": "https://yoursite.com/callback"
  }'

پاسخ موفق:

{
  "success": true,
  "data": {
    "transaction": {
      "authority": "20250107145623ABCDEF",
      "gateway_url": "https://sandbox.irandargah.com/startpay/20250107145623ABCDEF",
      "expires_at": "1404-10-17 15:11:23"
    },
    "meta": {
      "request_id": "sandbox_678abc123",
      "processing_time_ms": 45,
      "environment": "sandbox",
      "test_mode": true
    }
  },
  "message": "تراکنش با موفقیت ایجاد شد",
  "status_code": 100,
  "timestamp": "1404-10-17 14:56:23"
}

2. هدایت به درگاه

از gateway_url دریافتی در پاسخ استفاده کنید.

3. پرداخت با کارت تستی

4. دریافت Callback

پارامترهای بازگشتی:

https://yoursite.com/callback?
  authority=2025100121424146HC&
  status_code=201&
  message=پرداخت+در+انتظار+تایید+است&
  amount=100000&
  order_id=TEST-001&
  ref_id=123456789&
  card_pan=603799******6789

5. تأیید تراکنش

curl -X POST "https://sandbox.irandargah.com/v2/verifications" \
  -H "Authorization: Bearer YOUR_SANDBOX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "authority": "2025100121424146HC",
    "amount": 100000
  }'

محدودیت‌های محیط آزمایشی

محدودیت مقدار
تعداد تراکنش روزانه نامحدود
مبلغ حداکثر ۱۰,۰۰۰,۰۰۰ ریال
نرخ درخواست ۱۰ درخواست در ثانیه
زمان انقضای توکن ۳۰ روز

کدهای خطا

ایران‌درگاه از کدهای وضعیت HTTP استاندارد و همچنین یک کد وضعیت سفارشی (status_code) در بدنه‌ی پاسخ استفاده می‌کند. در هر پاسخ، فیلد status_code مقدار دقیق نتیجه‌ی عملیات را مشخص می‌کند و message معادل فارسی آن را برمی‌گرداند.

ساختار پاسخ خطا

تمام خطاها ساختار یکسانی دارند:

{
  "success": false,
  "error": {
    "message": "اطلاعات دریافتی معتبر نیست",
    "code": -2,
    "type": "validation_error",
    "details": {
      "inputs": ["مبلغ تراکنش قابل قبول نیست"]
    }
  },
  "status_code": -2,
  "timestamp": "1404-06-28 10:30:00",
  "meta": {
    "request_id": "req_error_001"
  }
}
فیلد نوع توضیح
success boolean همیشه false در پاسخ‌های خطا
error.message string پیام خطا به فارسی
error.code integer کد وضعیت سفارشی (همان status_code)
error.type string دسته‌بندی خطا (به جدول انواع خطا مراجعه کنید)
error.details object جزئیات بیشتر؛ در خطاهای اعتبارسنجی شامل خطای هر فیلد
status_code integer کد وضعیت سفارشی
timestamp string زمان پاسخ به تاریخ خورشیدی (YYYY-MM-DD HH:mm:ss)
meta.request_id string شناسه‌ی یکتای درخواست برای پیگیری با پشتیبانی

یکنواختی ساختار پاسخ

همه‌ی اندپوینت‌های v2 — پرداخت، تأیید، تراکنش‌ها، وب‌هوک‌ها، گزارش‌ها و احراز هویت — خطاها را در همان پاکت استاندارد بالا (error + status_code) بازمی‌گردانند. خطای اعتبارسنجی ورودی نیز در همه جا با کد -2، HTTP 422 و error.details.validation (کلیددار بر اساس نام فیلد) بازمی‌گردد.

تنها استثنا اندپوینت سلامت است که قالب سبکِ بررسی سرویس دارد (نه پاکت خطا):

اندپوینت شکل پاسخ
/health `{ "status": "ok" \

کدهای وضعیت HTTP

کد معنی
200 OK — درخواست موفق
201 Created — تراکنش جدید ایجاد شد
202 Accepted — درخواست تکراری هنوز در حال پردازش است (Idempotency)
400 Bad Request — درخواست نامعتبر یا نقض قانون تجاری
401 Unauthorized — توکن یا امضای نامعتبر
403 Forbidden — دسترسی مجاز نیست (IP، وضعیت ترمینال)
404 Not Found — تراکنش یا منبع یافت نشد
408 Request Timeout — مهلت درخواست قبلی (Idempotency) به‌سر رسید
409 Conflict — تداخل کلید Idempotency با درخواست متفاوت
422 Unprocessable Entity — خطا در اعتبارسنجی ورودی
429 Too Many Requests — عبور از حد مجاز درخواست
500 Internal Server Error — خطای داخلی سرور
503 Service Unavailable — سرویس بانکی یا کارمزد موقتاً در دسترس نیست

انواع خطا (Error Types)

هر خطا با یک type دسته‌بندی می‌شود تا مدیریت خطا در سمت شما ساده‌تر شود:

نوع کدهای نمونه توضیح
authentication_error -50, -51, -52 خطا در احراز هویت (توکن / IP)
authorization_error -53, 403 دسترسی مجاز نیست
validation_error -2 خطا در اعتبارسنجی ورودی
business_logic_error -6, -19, -21, -33 نقض قوانین تجاری
rate_limit_error -54 تعداد درخواست بیش از حد مجاز
server_error -31, 996 خطای داخلی سرور
gateway_error -101, -102, -103 خطا در ارتباط / امضای درگاه
success 100, 200 پاسخ موفق

مرجع کامل کدها

کدهای موفقیت و وضعیت در جریان

این کدها خطا نیستند و وضعیت طبیعی چرخه‌ی پرداخت را نشان می‌دهند.

کد پیام HTTP توضیح
100 تراکنش موفق بود 200 تراکنش با موفقیت ایجاد یا (در حالت direct_verify) تأیید شد
101 تراکنش قبلا وریفای شده است 200 تأیید تکراریِ تراکنشی که پیش‌تر با موفقیت وریفای شده (پاسخ idempotent)
200 اتصال به درگاه موفق بود 200 تأیید تراکنش با موفقیت انجام شد / اتصال به درگاه برقرار شد
201 پرداخت در حال انجام است 200 کاربر در صفحه‌ی بانک است؛ در callback به‌معنای «موفق، منتظر تأیید»

احراز هویت و دسترسی

این کدها توسط لایه‌ی احراز هویت پیش از رسیدن درخواست به موتور پرداخت بازگردانده می‌شوند.

کد پیام HTTP علت
-50 اطلاعات احراز هویت موجود نیست 401 هدر Authorization: Bearer ... ارسال نشده است
-51 اطلاعات احراز هویت نامعتبر است 401 توکن اشتباه، منقضی، یا باطل‌شده است
-52 IP در لیست سفید قرار ندارد 403 آدرس IP فرستنده در IP whitelist ترمینال نیست
-53 ترمینال غیرفعال یا مسدود شده است 403 ترمینال غیرفعال، معلق (suspended) یا تحت بررسی (under_review) است
-54 از حد مجاز اتصال عبور شده است 429 از rate limit ترمینال (پیش‌فرض ۱۰۰ درخواست در دقیقه) عبور کرده‌اید
403 ترمینال یافت نشد 403 ترمینال فعالی برای این توکن یافت نشد
451 قرارداد ارائه خدمات این پذیرنده امضا نشده یا منقضی شده است 400 قرارداد کارمزد درگاه امضا/تأیید نشده — در پنل کاربری امضا کنید

اعتبارسنجی ورودی

خطاهای مربوط به پارامترهای نامعتبر در درخواست پرداخت.

کد پیام HTTP علت
-2 اطلاعات دریافتی معتبر نیست 400 خطای کلی اعتبارسنجی (مبلغ، order_id، callback_url، …)
-10 مبلغ تراکنش قابل قبول نیست 400 مبلغ خارج از بازه‌ی مجاز (۱۰۰٬۰۰۰ تا ۴٬۰۰۰٬۰۰۰٬۰۰۰ ریال) است
-55 آدرس سایت و کال‌بک باید یکسان باشد 400 دامنه‌ی callback_url با دامنه‌ی ثبت‌شده‌ی ترمینال یکی نیست
-56 مبلغ نامعتبر است 400 فرمت amount نامعتبر است
-57 شماره سفارش نامعتبر است 400 order_id خالی یا بیش از ۵۰ کاراکتر یا دارای کاراکتر غیرمجاز
-58 شماره کارت نامعتبر است 400 فرمت card_number نادرست است
-59 آدرس کال‌بک نامعتبر است 400 callback_url خالی، طولانی‌تر از حد، یا بدون http(s)://
-60 توضیح نامعتبر است 400 description بیش از ۲۵۵ کاراکتر یا دارای < / > است
-61 کد مرچنت نامعتبر است 400 شناسه‌ی پذیرنده نامعتبر است
-62 کد همکار نامعتبر است 400 affiliate_code نامعتبر است (۴ تا ۶ کاراکتر حروف/عدد انگلیسی)
-63 directVerify is not boolean 400 مقدار direct_verify بولین (true/false) نیست
-8 موبایل نامعتبر است 400 فرمت mobile پذیرفته نشد
-9 موبایل یا تلفن نامعتبر است 400 شماره‌ی موبایل یا تلفن نامعتبر است

بازگشت از درگاه و فرآیند پرداخت

این کدها در مرحله‌ی هدایت کاربر به درگاه و بازگشت از آن رخ می‌دهند. بسیاری از آن‌ها به‌صورت صفحه‌ی خطا یا پارامتر status_code در callback ظاهر می‌شوند.

کد پیام علت
-1 تراکنش توسط کاربر لغو شد کاربر در صفحه‌ی بانک پرداخت را لغو کرد یا تراکنش ناموفق بود
-3 آدرس بازگشت همخوانی ندارد callback_url با مقدار ثبت‌شده همخوانی ندارد
-4 هدر Referer موجود نیست درخواست هدایت به درگاه فاقد هدر Referer است
-5 آدرس Referer نامعتبر است مقدار Referer قابل تجزیه نیست
-6 تراکنش یافت نشد یا ترمینال موجود نیست authority نامعتبر است یا ترمینال متناظر یافت نشد
-7 سایت ثبت شده با آدرس Referer همخوانی ندارد دامنه‌ی Referer با دامنه‌ی ثبت‌شده‌ی ترمینال یکی نیست
-11 مبلغ پرداخت شده با مبلغ تراکنش همخوانی ندارد بانک مبلغی متفاوت از مبلغ درخواست گزارش کرد — مبلغ برگشت می‌خورد
-12 شماره کارت پرداخت کننده با شماره کارت ارسالی همخوانی ندارد کارت پرداخت‌کننده با card_number ارسالی مغایرت دارد — برگشت می‌خورد
-13 تراکنش تکراری order_id یا authority تکراری است
-14 تراکنش قبلا تسویه/برگشت شده است تراکنش پیش‌تر تسویه یا برگشت داده شده است
-21 زمان مجاز برای ارسال تراکنش تمام شده است پنجره‌ی هدایت به درگاه (۲۰ دقیقه) منقضی شده است
-22 تراکنش به درگاه ارسال شد تلاش مجدد برای ارسال تراکنشی که قبلاً به بانک ارسال شده
-23 خطا در اتصال به درگاه بانکی خطا در ارتباط با PSP / سوئیچ بانکی
-24 خطا در موجودیت تراکنش بررسی موجودیت/در‌دسترس‌بودن تراکنش ناموفق بود
-30 خطا در فرآیند پرداخت، تراکنش برگشت شده است خطای میانه‌ی فرآیند پرداخت — مبلغ برگشت می‌خورد
-31 خطای ناشناخته خطای داخلی پیش‌بینی‌نشده (HTTP 500)
-32 تراکنش ناموفق تراکنش در وضعیت ناموفق نهایی شد
404 تراکنش یافت نشد تراکنشی با این authority وجود ندارد

تأیید تراکنش (Verification)

خطاهای فراخوانی POST /v2/verifications. این اندپوینت توسط موتور تأیید پردازش می‌شود و خطاها در قالب پاکت استاندارد با کدهای زیر بازمی‌گردند:

کد پیام HTTP علت
-2 خطا در اعتبارسنجی ورودی 422 پارامترهای ورودی (authority/amount/order_id) نامعتبرند
-19 شناسه یکتا، شماره سفارش یا مبلغ اشتباه است 400 تراکنش با authority/order_id/amount داده‌شده یافت نشد
-33 تراکنش دارای وضعیت صحیح برای وریفای نیست 400 تراکنش در وضعیتی نیست که قابل تأیید باشد (پرداخت‌نشده، ناموفق، …)
-31 خطای ناشناخته 500 خطای داخلی یا خطا در اتصال به PSP هنگام تأیید
403 ترمینال یافت نشد 403 ترمینال این درخواست یافت نشد

کدهای امضای درخواست (Signing Errors)

این کدها فقط برای ترمینال‌هایی صادر می‌شوند که قابلیت امضای درخواست (require_signature=true) روی آن‌ها فعال است.

کد پیام HTTP علت
-101 Missing signature headers (X-Signature, X-Timestamp) 401 هدر X-Signature یا X-Timestamp ارسال نشده است
-102 Request timestamp is invalid or expired (max 5 minutes) 401 اختلاف X-Timestamp با زمان سرور بیش از ۵ دقیقه است
-103 Invalid request signature 401 امضای X-Signature با محتوای درخواست همخوانی ندارد

خطاهای سامانه و کارمزد

این کدها معمولاً نشان‌دهنده‌ی مشکل پیکربندی سمت سرور هستند و در شرایط عادی به مرچنت بازنمی‌گردند. در صورت مشاهده با پشتیبانی تماس بگیرید.

کد پیام HTTP علت
405 Invalid PSP ID 400 شناسه‌ی PSP انتخاب‌شده در پیکربندی معتبر نیست
995 خطا در محاسبه کارمزد فرم پرداخت 400 خطای محاسبه‌ی کارمزد فرم پرداخت
996 خطا در محاسبه کارمزد درگاه 503 سرویس محاسبه‌ی کارمزد موقتاً در دسترس نیست
997 پیکربندی ترمینال برای تراکنش یافت نشد 400 ردیف terminal_config تراکنش موجود نیست
998 ترمینال اصلی یافت نشد 400 ترمینال اصلی برای محاسبه‌ی کارمزد یافت نشد
999 مبلغ کیف پول اصلی یافت نشد 400 ردیف wallet_amounts ترمینال موجود نیست

کلید Idempotency و کدهای آن

هنگام ارسال هدر Idempotency-Key، بسته به وضعیت درخواستِ قبلیِ همان کلید، یکی از پاسخ‌های زیر را دریافت می‌کنید:

HTTP پیام معنی
200 (پاسخ اصلی همراه با "idempotent_replay": true) کلید قبلاً با موفقیت پردازش شده؛ همان پاسخ ذخیره‌شده برگردانده شد
202 Request is still being processed درخواست قبلی با همین کلید هنوز در حال پردازش است (retry_after: 5)
400 Invalid idempotency key format فرمت کلید نامعتبر است (باید ۱۶ تا ۶۴ کاراکتر a-z A-Z 0-9 _ - باشد)
400 Previous request failed. Please use a new idempotency key... درخواست قبلی ناموفق بود؛ با کلید جدید دوباره تلاش کنید
408 Previous request timed out. Please retry. درخواست قبلی بیش از ۳۰ ثانیه معطل ماند؛ دوباره تلاش کنید
409 Request payload does not match the original request همان کلید با بدنه‌ای متفاوت ارسال شده است (تداخل)

محدودیت‌های API

محدودیت نرخ درخواست

محدودیت‌ها بر اساس توکن Bearer (یا IP در نبود توکن) به‌ازای هر دقیقه اعمال می‌شوند. در صورت فراتر رفتن، پاسخ HTTP 429 Too Many Requests دریافت خواهید کرد.

آدرس بدون امضا با امضای معتبر (X-Signature)
POST /v2/payments (ایجاد پرداخت) ۱۰۰ درخواست/دقیقه نامحدود
POST /v2/verifications (تأیید پرداخت) ۱۰۰ درخواست/دقیقه نامحدود
POST /v2/refunds (استرداد) ۳۰ درخواست/دقیقه نامحدود
GET /v2/reports/* (گزارش‌ها) ۶۰ درخواست/دقیقه نامحدود
GET /v2/transactions/* (تراکنش‌ها) ۶۰ درخواست/دقیقه نامحدود
POST /v2/webhooks/{subscribe,unsubscribe,test} ۱۰ درخواست/دقیقه (مستقل از امضا)
POST /v2/webhooks/test ۳ درخواست/دقیقه (مستقل از امضا)

محدودیت endpoint تولید امضا

POST /api/prepare-request سه محدودیت هم‌زمان دارد — اگر هر کدام پر شوند، پاسخ ۴۲۹ می‌گیرید:

محدودیت مقدار identifier
محدودیت per-IP ۱۰۰ درخواست/دقیقه آدرس IP
محدودیت per-token ۲۰۰ درخواست/دقیقه هدر X-API-Token (یا IP در نبودش)
محدودیت روزانه ۱۰٬۰۰۰ درخواست/روز هدر X-API-Token (یا IP در نبودش)

نمایش محدودیت در هدر بازگشتی

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1642248000
Retry-After: 60

پاسخ JSON خطا:

{
  "success": false,
  "error": {
    "message": "تعداد درخواست‌ها بیش از حد مجاز است",
    "code": -54,
    "type": "rate_limit_error"
  },
  "status_code": -54,
  "timestamp": "1404-06-29 10:30:00"
}

امنیت

HTTPS

تمام ارتباطات باید از طریق HTTPS انجام شود. درخواست‌های HTTP به طور خودکار به HTTPS تغییر مسیر می‌یابند.

API Token

توکن idg_live_… خود را در مکان امن (Vault، Secret Manager، یا متغیر محیطی سرور) نگهداری کنید. هرگز آن را در کد سمت کلاینت (مرورگر، اپ موبایل) قرار ندهید و در مخازن عمومی Git قرار نگذارید. در صورت نشت، فوراً از پنل کاربری ابطال اضطراری را بزنید (به بخش احراز هویت مراجعه کنید).

Idempotency

برای جلوگیری از تراکنش‌های تکراری، از هدر Idempotency-Key استفاده کنید.

IP Whitelist

می‌توانید دسترسی API خود را به IP های مشخص محدود کنید از طریق پنل کاربری.

امضای درخواست (Request Signing)

برای ترمینال‌هایی که قابلیت امضای درخواست (require_signature) فعال است، هر درخواست ارسالی باید با secret_key ترمینال امضا شده و دو هدر زیر ارسال شود:

هدر توضیح
X-Signature امضای HMAC-SHA256 محاسبه‌شده
X-Timestamp زمان Unix درخواست (ثانیه)

فرمول محاسبه امضا

payload    = "METHOD:endpoint:json_body:timestamp"
signature  = HMAC-SHA256(payload, secret_key)
بخش توضیح مثال
METHOD متد HTTP به حروف بزرگ POST
endpoint نام endpoint بدون /v2/ payments
json_body بدنه درخواست به فرمت JSON (بدون فاصله، UTF-8) {"amount":100000,...}
timestamp زمان Unix (ثانیه) — همان مقدار هدر X-Timestamp 1727800000

مثال عملی

<?php
$secretKey = 'your_secret_key';
$timestamp = time();

$method   = 'POST';
$endpoint = 'payments';
$body     = json_encode([
    'amount'       => 100000,
    'callback_url' => 'https://yoursite.com/callback',
    'order_id'     => 'ORDER-123',
], JSON_UNESCAPED_UNICODE);

$payload   = "{$method}:{$endpoint}:{$body}:{$timestamp}";
$signature = hash_hmac('sha256', $payload, $secretKey);

// ارسال هدرها
$headers = [
    'Authorization: Bearer YOUR_API_TOKEN',
    'X-Signature: ' . $signature,
    'X-Timestamp: ' . $timestamp,
    'Content-Type: application/json',
];
const crypto = require('crypto');

const secretKey = 'your_secret_key';
const timestamp = Math.floor(Date.now() / 1000);

const method   = 'POST';
const endpoint = 'payments';
const body     = JSON.stringify({
  amount:       100000,
  callback_url: 'https://yoursite.com/callback',
  order_id:     'ORDER-123',
});

const payload   = `${method}:${endpoint}:${body}:${timestamp}`;
const signature = crypto.createHmac('sha256', secretKey).update(payload).digest('hex');

const headers = {
  Authorization: 'Bearer YOUR_API_TOKEN',
  'X-Signature': signature,
  'X-Timestamp': String(timestamp),
  'Content-Type': 'application/json',
};
import hmac, hashlib, time, json

secret_key = 'your_secret_key'
timestamp  = str(int(time.time()))

method   = 'POST'
endpoint = 'payments'
body     = json.dumps({
    'amount':       100000,
    'callback_url': 'https://yoursite.com/callback',
    'order_id':     'ORDER-123',
}, ensure_ascii=False)

payload   = f"{method}:{endpoint}:{body}:{timestamp}"
signature = hmac.new(secret_key.encode(), payload.encode(), hashlib.sha256).hexdigest()

headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'X-Signature':   signature,
    'X-Timestamp':   timestamp,
    'Content-Type':  'application/json',
}

تولید امضا از طریق API

اگر نمی‌خواهید امضا را سمت کلاینت محاسبه کنید، می‌توانید از endpoint کمکی زیر استفاده کنید.

curl -X POST "https://ipg.irandargah.com/api/prepare-request" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "method":   "POST",
    "endpoint": "payments",
    "data": {
      "amount":       100000,
      "callback_url": "https://yoursite.com/callback",
      "order_id":     "ORDER-123"
    }
  }'
<?php
$body = [
    'method'   => 'POST',
    'endpoint' => 'payments',
    'data'     => [
        'amount'       => 100000,
        'callback_url' => 'https://yoursite.com/callback',
        'order_id'     => 'ORDER-123',
    ],
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://ipg.irandargah.com/api/prepare-request');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer YOUR_API_TOKEN',
    'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body, JSON_UNESCAPED_UNICODE));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$prepared = json_decode($response, true);
// $prepared['signature'], $prepared['timestamp'], $prepared['idempotency_key']
?>
const body = {
  method:   "POST",
  endpoint: "payments",
  data: {
    amount:       100000,
    callback_url: "https://yoursite.com/callback",
    order_id:     "ORDER-123",
  },
};

const response = await fetch(
  "https://ipg.irandargah.com/api/prepare-request",
  {
    method: "POST",
    headers: {
      Authorization:  "Bearer YOUR_API_TOKEN",
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  }
);

const prepared = await response.json();
// prepared.signature, prepared.timestamp, prepared.idempotency_key
body := map[string]interface{}{
    "method":   "POST",
    "endpoint": "payments",
    "data": map[string]interface{}{
        "amount":       100000,
        "callback_url": "https://yoursite.com/callback",
        "order_id":     "ORDER-123",
    },
}
jsonData, _ := json.Marshal(body)

req, _ := http.NewRequest("POST", "https://ipg.irandargah.com/api/prepare-request", bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()

var prepared map[string]interface{}
json.NewDecoder(resp.Body).Decode(&prepared)
body = {
    'method':   'POST',
    'endpoint': 'payments',
    'data': {
        'amount':       100000,
        'callback_url': 'https://yoursite.com/callback',
        'order_id':     'ORDER-123',
    },
}

response = requests.post(
    'https://ipg.irandargah.com/api/prepare-request',
    headers={
        'Authorization': 'Bearer YOUR_API_TOKEN',
        'Content-Type':  'application/json',
    },
    json=body
)

prepared = response.json()
# prepared['signature'], prepared['timestamp'], prepared['idempotency_key']
var body = new {
    method   = "POST",
    endpoint = "payments",
    data = new {
        amount       = 100000,
        callback_url = "https://yoursite.com/callback",
        order_id     = "ORDER-123",
    },
};

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_TOKEN");

var json    = JsonConvert.SerializeObject(body);
var content = new StringContent(json, Encoding.UTF8, "application/json");

var response = await client.PostAsync("https://ipg.irandargah.com/api/prepare-request", content);
var result   = await response.Content.ReadAsStringAsync();

پاسخ:

{
  "success":            true,
  "idempotency_key":    "idem_1727800000_abc123xyz",
  "signature_required": true,
  "signature":          "a1b2c3d4e5f6...",
  "timestamp":          "1727800000",
  "algorithm":          "HMAC-SHA256",
  "headers": {
    "X-Idempotency-Key": "idem_1727800000_abc123xyz",
    "X-Signature":       "a1b2c3d4e5f6...",
    "X-Timestamp":       "1727800000",
    "Content-Type":      "application/json"
  },
  "expires_at": "2025-10-01T10:35:00.000Z"
}

امضای دریافت‌شده ۵ دقیقه اعتبار دارد.

تأیید امضای پاسخ (Response Signature Verification)

سرور ایران‌درگاه پاسخ تمام endpointهای v2 را برای ترمینال‌هایی که secret_key دارند امضا می‌کند. دو هدر زیر به پاسخ اضافه می‌شوند:

هدر توضیح
X-Response-Signature امضای HMAC-SHA256 بدنه پاسخ
X-Response-Timestamp زمان Unix تولید پاسخ (ثانیه)

فرمول تأیید

payload          = response_body + ":" + X-Response-Timestamp
expected         = HMAC-SHA256(payload, secret_key)
is_valid         = timing_safe_compare(expected, X-Response-Signature)

بازه زمانی قابل قبول: ۵ دقیقه از زمان درج شده در X-Response-Timestamp.

مثال تأیید پاسخ

<?php
function verifyResponse(string $body, string $signature, string $timestamp, string $secretKey): bool
{
    if (abs(time() - (int)$timestamp) > 300) {
        return false; // timestamp منقضی شده
    }

    $payload  = "{$body}:{$timestamp}";
    $expected = hash_hmac('sha256', $payload, $secretKey);

    return hash_equals($expected, $signature);
}

// استفاده
$isValid = verifyResponse(
    $responseBody,
    $response->getHeader('X-Response-Signature'),
    $response->getHeader('X-Response-Timestamp'),
    'your_secret_key'
);
const crypto = require('crypto');

function verifyResponse(body, signature, timestamp, secretKey) {
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
    return false; // timestamp منقضی شده
  }

  const payload  = `${body}:${timestamp}`;
  const expected = crypto.createHmac('sha256', secretKey).update(payload).digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}
import hmac, hashlib, time

def verify_response(body: str, signature: str, timestamp: str, secret_key: str) -> bool:
    if abs(time.time() - int(timestamp)) > 300:
        return False  # timestamp منقضی شده

    payload  = f"{body}:{timestamp}"
    expected = hmac.new(secret_key.encode(), payload.encode(), hashlib.sha256).hexdigest()

    return hmac.compare_digest(expected, signature)

پشتیبانی

برای دریافت پشتیبانی فنی: