مقدمه
به API درگاه پرداخت ایراندرگاه خوش آمدید! این API با استاندارد snake_case برای تمامی فیلدهای ورودی و خروجی، امکان ایجاد تراکنشهای پرداخت آنلاین و تأیید آنها را فراهم میکند.
شما میتوانید از نمونه کدهای موجود در سمت چپ صفحه استفاده کنید. کدهای نمونه در زبانهای مختلف برنامهنویسی ارائه شدهاند!
ویژگیهای جدید
- ✅ توکن واحد: احراز هویت با یک Bearer Token (با پیشوند
idg_live_/idg_test_) - ✅ چرخش امن توکن: ۲۴ ساعت پنجرهی grace خودکار پس از هر rotation تا عملیات بدون قطعی انجام شود
- ✅ ابطال اضطراری: امکان باطل کردن فوری توکن از پنل کاربری در صورت نشت
- ✅ استاندارد نامگذاری: تمامی فیلدها با نامگذاری
snake_case(مانندorder_id,callback_url,ref_id) - ✅ ساختار پاسخ یکسان: همه پاسخها شامل
success,data,message,status_codeوtimestamp - ✅ Idempotency-Key: جلوگیری از تراکنشهای تکراری با هدر
- ✅ مدیریت خطای پیشرفته: ساختار خطا با جزئیات و دستهبندی شده
- ✅ جلوگیری از Race Condition: قفل یکتا بودن
order_idدر سطح دیتابیس
احراز هویت
ایران درگاه برای احراز هویت از یک توکن واحد استفاده میکند که برای ترمینال شما صادر و در اختیار شما قرار میگیرد.
فرمت توکن
توکنها با پیشوندِ بامعنی صادر میشوند تا محیط عملیاتی و آزمایشی از روی نگاه قابل تشخیص باشند:
| پیشوند | محیط |
|---|---|
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");
دریافت توکن
صدور و چرخش توکن فقط پس از فعال شدن درگاه انجام میشود. برای دریافت توکن جدید:
- وارد پنل کاربری شوید
- به بخش «درگاهها» بروید
- در صورت نیاز به توکن جدید، با پشتیبانی تماس بگیرید — توکن یکبار در پیام پاسخ ارسال میشود
چرخش توکن (Rotation)
زمانی که توکن چرخش پیدا میکند (rotation)، توکن قبلی بهصورت خودکار به مدت ۲۴ ساعت همچنان معتبر میماند. این پنجره برای انتقال آرام بدون قطعی طراحی شده است:
| لحظه | حالت |
|---|---|
T + 0 |
توکن جدید صادر میشود؛ توکن قدیمی هنوز معتبر است |
T + [0, 24h) |
هر دو توکن کار میکنند؛ زمان مناسب برای انتقال تدریجی |
T + 24h |
توکن قدیمی بهطور کامل باطل میشود — فقط توکن جدید کار میکند |
در طول این ۲۴ ساعت، هر درخواستی که با توکن قدیمی ارسال شود، در پاسخ خود این هدرهای هشدار را دریافت میکند:
| هدر | توضیح |
|---|---|
X-Token-Deprecated |
مقدار true — یعنی این توکن در حال انقضاست |
X-Token-Deprecated-Expires-At |
زمان دقیق انقضای توکن قدیمی (ISO 8601) |
اگر در سرور خود این هدرها را رصد کنید، میتوانید پیش از انقضا متوجه شوید کدام instance هنوز به توکن قدیمی متصل است.
ابطال اضطراری (Emergency Revoke)
اگر مشکوک شدید توکن لو رفته (مثلاً در گیتهاب کامیت کردهاید یا در گفتگوی تلگرام دیده شده):
- وارد پنل کاربری شوید
- ترمینال موردنظر را باز کنید ← دکمهی «مدیریت کلید امضا»
- در پایین صفحه، بخش قرمز «ناحیهی خطر» ← دکمهی «باطل کن — توکن لو رفته» را بزنید
پس از ابطال، با پشتیبانی تماس بگیرید تا توکن جدید برایتان صادر شود.
کلید 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 استفاده میشود که برای جلوگیری از تراکنشهای تکراری ضروری است.
آدرس درخواست
https://ipg.irandargah.com/v2/idempotency-key
پارامترهای پاسخ
| پارامتر | نوع | توضیح |
|---|---|---|
success |
boolean | وضعیت موفقیت درخواست |
idempotency_key |
string | کلید منحصر به فرد با پیشوند txn_ |
expires_in |
integer | مدت زمان اعتبار کلید به ثانیه (۸۶۴۰۰ = ۲۴ ساعت) |
usage |
string | راهنمای استفاده از کلید |
فرآیند پرداخت
فرآیند پرداخت در ایراندرگاه شامل مراحل زیر است:
- ایجاد تراکنش: درخواست پرداخت به آدرس
/v2/paymentsارسال میشود - هدایت کاربر: کاربر با استفاده از
authorityدریافتی به صفحه پرداخت هدایت میشود - پرداخت: کاربر عملیات پرداخت را در صفحه بانک انجام میدهد
- بازگشت: کاربر به
callback_urlشما برگردانده میشود - تأیید: درخواست تأیید به آدرس
/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"
}
}
این آدرس برای ایجاد یک تراکنش پرداخت جدید استفاده میشود.
آدرس درخواست
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"
}
}
این آدرس برای دریافت اطلاعات یک تراکنش پرداخت استفاده میشود.
آدرس درخواست
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"
}
}
این آدرس برای لغو یک تراکنش پرداخت استفاده میشود.
آدرس درخواست
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"
}
}
این آدرس پس از بازگشت کاربر از صفحه پرداخت برای تأیید نهایی تراکنش استفاده میشود.
آدرس درخواست
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"
}
}
این آدرس برای بررسی وضعیت تأیید یک تراکنش استفاده میشود.
آدرس درخواست
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"
}
}
این آدرس برای تلاش مجدد تأیید یک تراکنش ناموفق استفاده میشود.
آدرس درخواست
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"
}
}
این آدرس برای دریافت فهرست تراکنشها استفاده میشود.
آدرس درخواست
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"
}
}
این آدرس برای دریافت جزئیات کامل یک تراکنش استفاده میشود.
آدرس درخواست
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 استفاده میشود.
آدرس درخواست
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"
}
}
آدرس درخواست
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"
}
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 ارسال نمیشود.
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 شما ارسال میکند تا بتوانید پیادهسازی خود را پیش از رفتن به محیط عملیاتی تست کنید.
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"
}
}
این آدرس برای دریافت گزارش روزانه تراکنشها استفاده میشود.
آدرس درخواست
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"
}
}
آدرس درخواست
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 بدون تغییر در محیط آزمایشی قابل استفاده هستند، فقط:
- آدرس پایه را تغییر دهید
- از توکن تست استفاده کنید
- از کارتهای تستی استفاده کنید
مثال: ایجاد پرداخت در محیط آزمایشی
تنها تفاوت محیط آزمایشی با محیط عملیاتی در آدرس پایه و توکن است — همان درخواست و همان پاسخ. کافی است این دو را در زمان بیلد روی هر محیطی که میخواهید ست کنید:
# 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);
دریافت توکن تست
برای دریافت توکن تست:
- به پنل مدیریت محیط آزمایشی مراجعه کنید:
https://sandbox.irandargah.com/dashboard - از بخش
API Tokensیک توکن جدید ایجاد کنید - توکن را در کدهای تست خود استفاده کنید
تست فرآیند کامل
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. پرداخت با کارت تستی
- شماره کارت:
6037997123456789 - CVV2:
123 - تاریخ انقضا:
05/10 - رمز دوم (
OTP): هر عددی (در محیط آزمایشی قبول میشود)
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)
پشتیبانی
برای دریافت پشتیبانی فنی:
- ایمیل: contact@irandargah.com
- تلفن: ۰۳۱-۳۶۷۶۰۰۰۰
- پنل کاربری: https://panel.irandargah.com
- بخش پشتیبانی: https://irandargah.com/contact
- مستندات: https://docs.irandargah.com