تأیید حساب پذیرنده
ثبتنام را در ربات کامل کنید و منتظر تأیید حساب بمانید. تنها پذیرندگان تأییدشده به API عملیاتی دسترسی دارند.
از صدور کلید API تا دریافت امن رویداد پرداخت؛ راهنمای یکپارچهسازی فاکتورهای 2Pey برای تیمهای فنی و عملیاتی.
کل جریان در پنج گام روشن انجام میشود. تمام تنظیمات اتصال از مسیر «تنظیمات پذیرنده ← اتصال، کلیدها و مستندات» در ربات در دسترس است.
ثبتنام را در ربات کامل کنید و منتظر تأیید حساب بمانید. تنها پذیرندگان تأییدشده به API عملیاتی دسترسی دارند.
در «اتصال، کلیدها و مستندات ← مدیریت کلید API» کلید بسازید و همان لحظه در سامانه خود ذخیره کنید؛ بعداً از ربات قابل بازیابی نیست.
در بخش اتصال، نشانی امن وبهوک و رمز امضا را ثبت کنید تا بتوانید پیامهای ارسالی را بررسی کنید.
فاکتور عمومی را بدون تعیین پرداختکننده بسازید، یا برای فاکتور خصوصی یک شناسهٔ تأییدپذیر وارد کنید.
امضا را روی بدنه خام اعتبارسنجی، رویداد را با Event ID ذخیره و سپس پاسخ موفق 2xx برگردانید.
https://api.2pey.comAuthorization: Bearer <api-key>application/jsonبرای جلوگیری از ساخت فاکتور تکراری هنگام timeout یا retry، برای هر سفارش یک Idempotency-Key پایدار با طول ۱ تا ۱۲۸ کاراکتر بفرستید. حذف شناسهٔ پرداختکننده فاکتور عمومی میسازد؛ برای فاکتور خصوصی، شناسهٔ تأییدشدهٔ همان پرداختکننده را بفرستید.
curl -X POST 'https://api.2pey.com/v1/invoices' \
-H 'Authorization: Bearer <api-key>' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-8472-v1' \
--data '{
"payer_telegram_id": 123456789,
"amount_toman": 5000000,
"description": "سفارش شماره ۸۴۷۲",
"merchant_reference": "order-8472"
}'
{
"public_id": "inv_Lysi_CWcMNFLzS9e",
"status": "pending",
"payer_telegram_id": 123456789,
"amount_toman": 5000000,
"description": "سفارش شماره ۸۴۷۲",
"merchant_reference": "order-8472",
"due_at": "2026-10-10T12:47:00Z",
"created_at": "2026-10-03T12:47:00Z",
"paid_at": null,
"payment_url": "https://t.me/2PeyRobot?start=pay_...",
"miniapp_url": "https://2pey.com/checkout?invoice=inv_Lysi_CWcMNFLzS9e&access=..."
}
همه endpointها به هدر Bearer نیاز دارند. پاسخها JSON هستند و زمانها با ISO-8601 برگردانده میشوند.
ایجاد، خواندن، ویرایش و لغو فاکتور با کلید API
تغییر وضعیت با امضای HMAC و شناسه یکتای رویداد
/v1/invoicesفاکتور تازه ایجاد میکند. ارسال دوباره همان Idempotency-Key و همان payload، پاسخ فاکتور قبلی را با کد 200 برمیگرداند.
| فیلد | نوع | الزام | توضیح |
|---|---|---|---|
allowed_source_pan | string | null | خیر | کارت مبدأ مجاز برای کارتبهکارت، بهصورت شماره معتبر ۱۶ رقمی. حذف یا null در ایجاد یعنی بدون محدودیت. در ویرایش، حذف فیلد محدودیت فعلی را حفظ و null آن را پاک میکند. فقط چهار رقم آخر در پاسخ نشان داده میشود. |
require_login | boolean | خیر | برای فاکتور عمومی: با مقدار true، پرداخت فقط پس از ورود با حساب تأییدشده انجام میشود. پیشفرض false و پرداخت مهمان مجاز است. این گزینه پرداختکنندهٔ مشخص تعیین نمیکند. |
payer_telegram_id | integer | خیر | برای سازگاری؛ فاکتور خصوصی با شناسهٔ تلگرام. برای فاکتور عمومی حذف شود. |
payer | object | خیر | فاکتور خصوصی با type و value: نوعهای telegram_id، phone، email یا account_id. در زمان پرداخت، گیرنده باید مالکیت همان شناسه را تأیید کند؛ برای موبایل و ایمیل، ثبتنام قبلی در زمان صدور لازم نیست. |
amount_toman | integer | بله | مبلغ صحیح به تومان؛ بیشتر از صفر و حداکثر ۱۰٬۰۰۰٬۰۰۰٬۰۰۰ |
description | string | خیر | شرح قابل نمایش به پرداختکننده؛ حداکثر ۵۰۰ کاراکتر |
due_at | datetime | خیر | زمان ISO-8601 دارای timezone؛ پیشفرض ۷ روز، حداکثر ۹۰ روز آینده |
merchant_reference | string | خیر | شناسه یکتای سفارش در سامانه شما؛ حداکثر ۱۲۸ کاراکتر |
کارت مبدأ اعلامی: در کارتبهکارت، پرداختکننده کارت ذخیرهشدهٔ خود را انتخاب یا کارت تازه وارد میکند. این انتخاب و استعلام اطلاعات کارت به معنی تأیید هویت، مالکیت بانکی یا اثبات کارت واقعی انتقال نیست؛ احراز الزامی جداگانه اجرا میشود. محدودیت allowed_source_pan فقط کارت اعلامشده در این جریان را کنترل میکند و پرداخت کیف پول یا رمزارز را محدود نمیکند. شمارهٔ کامل کارت را در گزارشها، لینکها و webhookها ذخیره نکنید.
اگر هر دو فیلد پرداختکننده حذف شوند، فاکتور عمومی است و دارندهٔ لینک امن پرداخت میتواند مهمان پرداخت کند. پاسخ ایجاد شامل payer_type و miniapp_url دارای توکن دسترسی است؛ لینک را مثل رمز سفارش محرمانه نگه دارید. شناسهٔ فاکتور بهتنهایی مجوز پرداخت نیست. برای فاکتور خصوصی، پرداختکننده باید با همان شناسه وارد شود.
curl -X POST 'https://api.2pey.com/v1/invoices' \\
-H 'Authorization: Bearer <api-key>' \\
-H 'Content-Type: application/json' \\
-H 'Idempotency-Key: public-order-8472-v1' \\
--data '{"amount_toman":500000,"description":"سفارش ۸۴۷۲","merchant_reference":"order-8472"}'{
"payer": {"type": "email", "value": "customer@example.com"},
"amount_toman": 500000,
"merchant_reference": "order-8473"
}/v1/invoices?offset=0&limit=20فهرست صفحهبندیشده فاکتورهای همین پذیرنده را برمیگرداند. offset از صفر و limit از ۱ تا ۱۰۰ است؛ مقدار پیشفرض limit برابر ۲۰ است.
curl 'https://api.2pey.com/v1/invoices?offset=0&limit=20' \
-H 'Authorization: Bearer <api-key>'{
"items": [{
"public_id": "inv_Lysi_CWcMNFLzS9e",
"payer_telegram_id": 123456789,
"amount_toman": 5000000,
"description": "سفارش شماره ۸۴۷۲",
"merchant_reference": "order-8472",
"status": "pending",
"due_at": "2026-10-10T12:47:00Z",
"created_at": "2026-10-03T12:47:00Z",
"paid_at": null,
"payment_url": null,
"miniapp_url": "https://2pey.com?invoice=inv_Lysi_CWcMNFLzS9e"
}],
"offset": 0,
"limit": 20,
"total": 1,
"has_more": false
}/v1/invoices/{public_id}آخرین وضعیت یک فاکتور را با شناسه عمومی دریافت میکند. شناسه باید متعلق به همان پذیرنده باشد. پاسخ، همان فیلدهای نمونه ساخت فاکتور را دارد؛ payment_url در خواندن مجدد معمولاً null است.
curl 'https://api.2pey.com/v1/invoices/inv_Lysi_CWcMNFLzS9e' \
-H 'Authorization: Bearer <api-key>'{
"public_id": "inv_Lysi_CWcMNFLzS9e",
"payer_telegram_id": 123456789,
"amount_toman": 5000000,
"description": "سفارش شماره ۸۴۷۲",
"merchant_reference": "order-8472",
"status": "pending",
"due_at": "2026-10-10T12:47:00Z",
"created_at": "2026-10-03T12:47:00Z",
"paid_at": null,
"payment_url": null,
"miniapp_url": "https://2pey.com?invoice=inv_Lysi_CWcMNFLzS9e"
}/v1/invoices/{public_id}فقط فیلدهای ارسالی را ویرایش میکند: amount_toman، description ، due_at، allowed_source_pan، source_bank_name، source_holder_name و یکی از allowed_destination_card_id یا allowed_destination_pan. فاکتور باید در وضعیت pending، منقضینشده و بدون هیچ تخصیص قبلی کارت پرداخت باشد. payer_telegram_id و merchant_reference تغییرپذیر نیستند؛ برای تغییر آنها فاکتور را لغو و فاکتور تازه ایجاد کنید.
curl -X PATCH 'https://api.2pey.com/v1/invoices/inv_Lysi_CWcMNFLzS9e' \
-H 'Authorization: Bearer <api-key>' \
-H 'Content-Type: application/json' \
--data '{"amount_toman": 4800000, "description": "سفارش اصلاحشده ۸۴۷۲"}'پاسخ موفق 200 و شکل آن InvoiceView است. بدنه خالی یا فیلد ناشناخته را ارسال نکنید.
{
"public_id": "inv_Lysi_CWcMNFLzS9e",
"payer_telegram_id": 123456789,
"amount_toman": 4800000,
"description": "سفارش اصلاحشده ۸۴۷۲",
"merchant_reference": "order-8472",
"status": "pending",
"due_at": "2026-10-10T12:47:00Z",
"created_at": "2026-10-03T12:47:00Z",
"paid_at": null,
"payment_url": null,
"miniapp_url": "https://2pey.com?invoice=inv_Lysi_CWcMNFLzS9e"
}/v1/invoices/{public_id}حذف نرم است: فاکتور pending را به وضعیت cancelled میبرد و رویداد invoice.cancelled تولید میکند. سابقه پرداخت و حسابرسی پاک نمیشود. فاکتور پرداختشده، منقضیشده یا دارای سابقه تخصیص کارت پرداخت قابل حذف نیست.
curl -X DELETE 'https://api.2pey.com/v1/invoices/inv_Lysi_CWcMNFLzS9e' \
-H 'Authorization: Bearer <api-key>'پاسخ موفق 200 شامل نمای فاکتور با "status": "cancelled" است. برای سازگاری، مسیر POST /v1/invoices/{public_id}/cancel نیز موجود است.
{
"public_id": "inv_Lysi_CWcMNFLzS9e",
"payer_telegram_id": 123456789,
"amount_toman": 5000000,
"description": "سفارش شماره ۸۴۷۲",
"merchant_reference": "order-8472",
"status": "cancelled",
"due_at": "2026-10-10T12:47:00Z",
"created_at": "2026-10-03T12:47:00Z",
"paid_at": null,
"payment_url": null,
"miniapp_url": "https://2pey.com?invoice=inv_Lysi_CWcMNFLzS9e"
}/v1/invoices/{public_id}/cancelفاکتور در انتظار پرداخت را لغو میکند. فاکتور پرداختشده، منقضیشده یا دارای سابقه تخصیص کارت پرداخت قابل لغو نیست و پاسخ تعارض دریافت میکند. درخواست تکراری برای فاکتور لغوشده همان وضعیت لغوشده را برمیگرداند.
curl -X POST 'https://api.2pey.com/v1/invoices/inv_Lysi_CWcMNFLzS9e/cancel' \
-H 'Authorization: Bearer <api-key>'کلید API را فقط در کد سمت سرور نگه دارید. پیش از اجرا، ORDER_ID و PAYER_TELEGRAM_ID را در متغیرهای محیطی تنظیم کنید. نمونهٔ Python به pip install requests و JavaScript به Node.js 18+ نیاز دارد.
import os
import requests
order_id = os.environ["ORDER_ID"]
response = requests.post(
"https://api.2pey.com/v1/invoices",
headers={
"Authorization": f"Bearer {os.environ['TWOPEY_API_KEY']}",
"Idempotency-Key": f"invoice:create:{order_id}",
},
json={
"payer_telegram_id": int(os.environ["PAYER_TELEGRAM_ID"]),
"amount_toman": 5000000,
"merchant_reference": order_id,
},
timeout=15,
)
response.raise_for_status()
invoice = response.json()
print(invoice["public_id"])const orderId = process.env.ORDER_ID;
const payerId = Number(process.env.PAYER_TELEGRAM_ID);
if (!Number.isSafeInteger(payerId) || payerId <= 0) throw new Error('Invalid payer ID');
const response = await fetch('https://api.2pey.com/v1/invoices', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TWOPEY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': `invoice:create:${orderId}`,
},
body: JSON.stringify({
payer_telegram_id: payerId,
amount_toman: 5000000,
merchant_reference: orderId,
}),
});
if (!response.ok) throw new Error(`2Pey API: ${response.status}`);
const invoice = await response.json();
console.log(invoice.public_id);| کد | معنا | اقدام پیشنهادی |
|---|---|---|
200 | موفق یا replay همان درخواست idempotent | پاسخ را مانند موفقیت عادی پردازش کنید. |
201 | فاکتور جدید ساخته شد | public_id را کنار سفارش ذخیره کنید. |
401 / 403 | کلید نامعتبر یا دسترسی ناکافی | کلید و وضعیت پذیرنده را در ربات بررسی کنید. |
404 | فاکتور برای این پذیرنده پیدا نشد | شناسه عمومی و مالکیت پذیرنده را بررسی کنید. |
409 | تعارض وضعیت، سابقه تلاش پرداخت یا Idempotency-Key با payload دیگر | ابتدا وضعیت فاکتور و درخواست قبلی را بررسی کنید. اگر ویرایش یا لغو دیگر مجاز نیست، برای سفارش جدید فاکتور تازه بسازید. |
422 | اعتبارسنجی ورودی ناموفق | نوع مبلغ، Telegram ID و timezone تاریخ را اصلاح کنید. |
429 | سهمیهٔ درخواست یا ایجاد فاکتور تمام شده | در محدودیت ترافیک، بهاندازهٔ Retry-After ثانیه صبر کنید. برای سقف روزانه، زمان بازشدن سهمیه را بررسی کنید؛ درخواست مالی را با همان Idempotency-Key تکرار کنید. |
پیشفرض هر پذیرنده ۱۲۰۰ درخواست در پنجرهٔ لغزان ۶۰ ثانیه است؛ ساخت فاکتور از همین مجموع، حداکثر ۳۰۰ درخواست دارد. سهمیه میان کلیدهای یک پذیرنده مشترک است و ممکن است براساس تنظیمات خدمات تغییر کند. سقف روزانهٔ فاکتور نیز مستقل باقی میماند.
پاسخ 429 محدودسازی ترافیک دارای Retry-After به ثانیه است. هدرهای X-RateLimit-Limit، X-RateLimit-Remaining و X-RateLimit-Window سهمیهٔ پاسخ موفق را نشان میدهند. پاسخ 503 میتواند به معنی شلوغی موقت باشد؛ با تأخیر و کمی زمان تصادفی دوباره تلاش کنید.
در خطای ارتباط، 502 یا 504، نتیجهٔ عملیات مالی را نامعلوم در نظر بگیرید. ابتدا وضعیت فاکتور را دریافت کنید. تکرار ساخت فاکتور باید با همان Idempotency-Key و همان داده باشد.
payer_telegram_id ثبت شده است.due_at باید ISO-8601 و دارای offset زمانی مانند +03:30 یا Z باشد.2Pey تغییرات چرخه عمر فاکتور را با POST به URL ثبتشده ارسال میکند. endpoint شما باید عمومی، HTTPS و سریع باشد.
رویداد invoice.updated پس از ویرایش موفق PATCH منتشر میشود. مانند سایر رویدادها ممکن است تحویل آن تکرار شود؛ با Event ID پردازش تکراری را حذف کنید.
https://api.2pey.com و صفحهٔ پرداخت برابر
https://2pey.com است. مسیرهای API، کلیدها و شناسههای قبلی معتبرند.
هر وبهوک یک بار ارسال میشود؛ هدرهای قبلی X-SyncPay-* نیز با همان
مقادیر همراه هدرهای جدید هستند. نامهای قبلی SDK و متغیرهای محیطی در بستهٔ Python
پشتیبانی میشوند؛ نامهای TWOPEY_* اولویت دارند.| هدر | محتوا |
|---|---|
X-2Pey-Event | نوع رویداد، برای مثال invoice.paid |
X-2Pey-Event-Id | شناسه یکتای تحویل؛ مبنای deduplication |
X-2Pey-Timestamp | timestamp مورد استفاده در امضا |
X-2Pey-Signature | امضای HMAC با پیشوند sha256= |
import hashlib
import hmac
def verify_twopey(raw_body: bytes, headers, secret: str) -> bool:
timestamp = headers["X-2Pey-Timestamp"]
received = headers["X-2Pey-Signature"]
signed = timestamp.encode("utf-8") + b"." + raw_body
digest = hmac.new(
secret.encode("utf-8"), signed, hashlib.sha256
).hexdigest()
expected = "sha256=" + digest
return hmac.compare_digest(expected, received)
# 1) raw bytes را از request بخوانید
# 2) امضا را بررسی کنید
# 3) Event ID را بهصورت unique ذخیره کنید
# 4) پس از ثبت پایدار، پاسخ 2xx بدهیدconst crypto = require('node:crypto');
function verifyTwoPey(rawBody, headers, secret) {
const timestamp = headers['x-2pey-timestamp'];
const received = headers['x-2pey-signature'];
const signed = Buffer.concat([
Buffer.from(timestamp + '.', 'utf8'), rawBody
]);
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(signed)
.digest('hex');
const a = Buffer.from(expected, 'utf8');
const b = Buffer.from(received || '', 'utf8');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}برای جلوگیری از replay، سن timestamp را در یک پنجره زمانی کوتاه (برای مثال ۵ دقیقه) بررسی کنید. سپس امضا را با مقایسه زمان ثابت بسنجید. پنجره زمانی را با زمان سرور خود و تأخیر تحویل هماهنگ کنید.
ممکن است تحویل وبهوک در خطا یا timeout تکرار شود. ابتدا رویداد را با X-2Pey-Event-Id در یک ستون unique ثبت کنید، سپس منطق کسبوکار را اجرا کنید. تنها پس از ثبت پایدار پاسخ 2xx بدهید.
برای آزمایش، یک نشانی امن روی سامانه خودتان بسازید و از رمز جداگانه تست استفاده کنید.
curl -X POST 'https://api.2pey.com/v1/invoices' \
-H 'Authorization: Bearer <test-api-key>' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: webhook-test-001' \
--data '{
"payer_telegram_id": 123456789,
"amount_toman": 10000,
"description": "تست اتصال وبهوک"
}'Telegram ID حساب فعلی با payer_telegram_id فاکتور یکسان نیست. شناسه عددی کاربر را اصلاح و یک فاکتور جدید صادر کنید؛ لینک قابل انتقال به حساب دیگر نیست.
لینک ناقص، دستکاریشده یا مربوط به فاکتوری ناشناخته است. دقیقاً از مقدار payment_url پاسخ API استفاده کنید و آن را بازسازی نکنید.
زمان due_at گذشته است. فاکتور منقضی دوباره فعال نمیشود؛ فاکتور تازهای با زمان timezone-aware آینده ایجاد کنید.
کاربر باید قبلاً ربات را Start کرده باشد و آن را مسدود نکرده باشد. حتی بدون اعلان، لینک پرداخت را میتوانید از کانال امن خودتان در اختیار همان کاربر بگذارید.
معمولاً بدنه JSON پیش از محاسبه امضا parse یا دوباره serialize شده، secret اشتباه است، یا timestamp از هدر درست خوانده نشده. HMAC را دقیقاً روی timestamp، یک نقطه و بایتهای خام بدنه حساب کنید.
فاکتور باید pending و منقضینشده باشد و هیچ کارت پرداختی در گذشته به آن تخصیص نیافته باشد. وضعیت را با GET بررسی کنید؛ در صورت نیاز فاکتور تازه بسازید.
خیر. DELETE لغو نرم انجام میدهد و رکورد فاکتور و سابقه آن برای حسابرسی باقی میماند.
مقصد باید از اینترنت عمومی قابل دسترس و دارای HTTPS معتبر باشد. firewall، DNS، certificate و timeout پاسخ را بررسی کنید؛ endpoint محلی یا private IP قابل تحویل نیست.
درخواستها روی API واقعی و دادههای تولید اجرا میشوند. تنها با انتخاب دکمه ارسال، درخواست فرستاده میشود؛ ایجاد، ویرایش و لغو تأیید دوم دارند.
هنوز درخواستی ارسال نشده است.
در روش network چرخهٔ همکاران حفظ میشود. در روش direct فقط کارتهای خود پذیرنده نمایش داده میشوند؛ اصل فاکتور به کارت شما میرود و هزینهٔ خدمات جداگانه با رمزارز تسویه میشود.
کارتها، اتصال APK و کلید احراز را از «نوع همکاری» در ربات مدیریت کنید. بستهها تنها پس از فعالسازی مدیر قابل خریدند. پلنها هم مدت (حداکثر ۳۰ روز) و هم سهمیه دارند؛ پرداخت موفق از هر سه روش یک سهمیه مصرف میکند. پس از پایان پلن، تعرفهٔ مستقیم عمومی یا اختصاصی اعمال میشود. هزینهٔ پرداخت کارتی به بدهی خدمات اضافه میشود؛ در پرداخت کیف پولی یا رمزارزی از تسویه کسر میشود و دوباره بدهی ثبت نمیشود. تسویهٔ دوره با رسیدن به جمع پرداختهای کارتی یا فاصلهٔ روز تعیینشده لازم است. پیش از خرید پلن، هزینههای قبلی را تسویه کنید.
GET /v1/merchant/services
GET /v1/merchant/services/bills?page=0&limit=20
POST /v1/merchant/services/bills/issue
PUT /v1/merchant/services/receiving-mode {"mode":"direct"}
PUT /v1/merchant/services/plan {"plan":"package"} # monthly = percentage mode
POST /v1/merchant/services/packages/{id}/purchase {"asset":"USDT"}
POST /v1/merchant/services/bills/{id}/pay {"asset":"GRAM"}
POST /v1/merchant/services/packages/{id}/transfer {"asset":"GRAM","network":"TON"}
POST /v1/merchant/services/bills/{id}/transfer {"asset":"USDT","network":"TRC20"}
POST /v1/merchant/services/deposits/{deposit_id}/txid {"txid":"..."}تمام درخواستها همان کلید API پذیرنده را میخواهند. خرید بسته و درخواست انتقال باید هدر Idempotency-Key داشته باشند. انتقال تنها با مبلغ دقیق، دارایی، مقصد، زمان و تأیید زنجیره تسویه میشود؛ هش مالک واریز را تعیین نمیکند.
from twopey_client import TwoPeyClient
client = TwoPeyClient()
account = client.service_account()
client.set_receiving_mode("direct")
# Choose a real enabled package ID from account["packages"].
# client.purchase_package(package_id, asset="USDT", idempotency_key="order-001")
# client.pay_service_bill(bill_id, asset="GRAM")روش رزرو جاری ثابت میماند. صورتحساب ماهانه بر اساس ماه شمسی و ساعت تهران صادر میشود؛ نبود نرخ معتبر، صورتحساب سررسیددار ایجاد نمیکند. بدهی معوق دریافت جدید هر دو روش را متوقف میکند. برای بازپرداخت مستقیم، بازپرداخت واقعی بانکی و تأیید مالی لازم است.
هر پذیرنده، چه شبکهای و چه مستقیم، میتواند مبدأ فاکتور را تعیین کند. تعیین مقصد فقط برای پذیرندهٔ مستقیم ممکن است. مقصد باید کارت فعال و از قبل ثبتشدهٔ همان پذیرنده باشد؛ کارت شخص دیگر یا کارت ثبتنشده پذیرفته نمیشود.
GET /v1/merchant/direct-cards
Authorization: Bearer YOUR_MERCHANT_API_KEY
POST /v1/invoices
Authorization: Bearer YOUR_MERCHANT_API_KEY
Idempotency-Key: order-example-001
Content-Type: application/json
{
"amount_toman": 580000,
"allowed_source_pan": "SOURCE_CARD_NUMBER",
"source_bank_name": "بانک مبدأ",
"source_holder_name": "نام صاحب کارت مبدأ",
"allowed_destination_card_id": 123
}
برای مقصد یکی از allowed_destination_card_id یا allowed_destination_pan را بفرستید، نه هر دو. اگر شمارهٔ مقصد را بفرستید، سامانه آن را فقط میان کارتهای فعال خودتان جستوجو میکند و شناسهٔ کارت را ثبت میکند؛ کارت جدید ساخته نمیشود. پاسخ فاکتور شناسهٔ مقصد و چهار رقم آخر مبدأ را برمیگرداند.
در مبدأ تعیینشده، فیلدهای اختیاری source_bank_name و source_holder_name همراه allowed_source_pan پذیرفته میشوند. اگر هر دو کامل باشند، بدون استعلام بهعنوان اطلاعات اعلامیِ همان فاکتور نمایش داده میشوند؛ نام بانکِ شناختهشده از پیششماره کارت گرفته میشود. اطلاعات اعلامی به سوابق استعلامشدهٔ کاربر تبدیل نمیشوند و جایگزین احراز الزامی نیستند. اطلاعات استعلامشدهٔ همان پرداختکننده تا ۲۴ ساعت قابل استفادهٔ مجدد است. اگر اطلاعات کافی موجود نباشد، استعلام فقط با کلید API.IR خود پذیرنده انجام میشود؛ در حالت شبکهای از کلید همکار و در هیچکدام از کلید سیستم بهعنوان جایگزین استفاده نمیشود. پذیرندهٔ شبکهای نیز میتواند کلید استعلام خود را از ربات یا بخش کلیدهای مینیاپ تنظیم کند. مقصد ثابت همچنان کارت ثبتشدهٔ خود پذیرنده است و مشخصاتش از همان کارت خوانده میشود. شمارهٔ واقعی مبدأ انتقال از پیامک فعلی قابل اثبات نیست.
در ویرایش فاکتورِ بدون تلاش پرداخت، نفرستادن فیلد مقصد یعنی حفظ مقدار قبلی و مقدار null یعنی پاککردن آن. تکثیر، محدودیتها را حفظ و صلاحیت مقصد را دوباره کنترل میکند. اگر مقصد تعیینشده غیرفعال، حذف، تعویض یا برای مبلغ نامناسب شود، پرداخت کارتی به کارت دیگری هدایت نمیشود. فاکتور دارای مقصد ثابت، حتی پس از تغییر نوع همکاری، دریافت مستقیم به همان کارت را حفظ میکند؛ انتخاب مقصد جدید برای فاکتورهای تازه است. این گزینهها روش کیف پول یا رمزارز را محدود نمیکنند.
cards = client.direct_cards()["items"]
# Choose your own active destination card id.
invoice = client.create_invoice(
amount_toman=580000,
allowed_source_pan=os.environ["TWOPEY_ALLOWED_SOURCE_PAN"],
allowed_destination_card_id=cards[0]["id"],
merchant_reference="order-example-001",
)
client.update_invoice(invoice["public_id"], allowed_destination_card_id=None)اگر استعلام کارت مبدأ تعیینشده پاسخ موفق ولی فاقد نام صاحب کارت یا اطلاعات لازم برای تشخیص بانک کارت بدهد، وضعیت فاکتور به card_error تغییر میکند و پرداخت متوقف میشود. این وضعیت به معنی «اطلاعات کارت قابل تأیید نبود» است، نه اثبات قطعی نامعتبر بودن حساب. یک رویداد invoice.card_validation_failed در همان تراکنش ثبت و با همان امضا، تکرار امن و سیاست ارسال وبهوکهای فعلی تحویل میشود.
{"event":"invoice.card_validation_failed","invoice":{
"id":"inv_example","status":"card_error",
"card_validation_error":"source_card_details_missing"
}}شماره کارت، نام صاحب کارت، کلید و پاسخ خام بانک در این رویداد ارسال نمیشوند. برای ادامه پس از خطای اطلاعات، فاکتور تازه با اطلاعات اصلاحشده صادر کنید. خطای اتصال، timeout، نبود/اشکال کلید و پاسخ ناموفق یا نامفهوم سرویس، فاکتور را card_error نمیکنند و امکان تلاش دوباره باقی میماند. ساختار نامعتبر ورودی پیش از صدور با 422 رد میشود و برای فاکتورِ ایجادنشده وبهوک صادر نمیشود.
این وضعیت مربوط به برنامهٔ بانکی APK است، نه اعتبار کلید API پذیرنده. کلید API معتبر برای همهٔ درخواستها لازم است و فقط روی سرور شما نگهداری میشود.
GET https://api.2pey.com/v1/merchant/connection
Authorization: Bearer YOUR_MERCHANT_API_KEY
PUT https://api.2pey.com/v1/merchant/services/offline-cards
Authorization: Bearer YOUR_MERCHANT_API_KEY
Content-Type: application/json
{"show_cards_when_apk_offline": true}
تنظیم آفلاین فقط در حالت مستقیم قابل تغییر است و پیشفرض آن false است. فعالکردن آن فقط شرط آنلاینبودن APK را برای کارتهای خودتان برمیدارد؛ سقفها، مبلغ، احراز، بدهی خدمات و قواعد تأیید پرداخت همچنان برقرارند. هنگام قطع APK دریافت و تأیید پیامک میتواند با تأخیر انجام شود؛ قطع اتصال، اثبات واریز یا مجوز تأیید خودکار پرداخت نیست. حالت شبکهای تغییری نمیکند.
wss://api.2pey.com/v1/merchant/connection/ws
// First frame, within 8 seconds:
{"type":"auth","api_key":"YOUR_MERCHANT_API_KEY"}
// Initial snapshot and subsequent changes:
{"type":"connection.status","sequence":1,"data":{
"merchant_public_id":"mrc_example","receiving_mode":"direct",
"apk_connected":false,"apk_ready":false,"connection_status":"disconnected",
"show_cards_when_apk_offline":true,"cards_may_be_shown":true,
"active_cards_count":2,"blocked_overdue":false,
"last_seen_at":"2026-10-15T08:00:00+00:00","checked_at":"2026-10-15T08:01:00+00:00"
}}
// Connection heartbeat; not a new APK state:
{"type":"heartbeat","checked_at":"...","last_seen_at":"..."}
apk_connected اتصال معتبر دستگاه و apk_ready اتصال همراه با فعالبودن پایش APK است؛ هر دو ممکن است هنگام نبود پاسخ معتبر null باشند. مقدار false قطع/غیرفعالبودن مشاهدهشده و null وضعیت نامشخص است. برای دکمهٔ ربات خودتان میتوانید همین مقدارها را استفاده کنید؛ در صورت قطع وبسوکت، وضعیت قبلی را قطعی فرض نکنید.
cards_may_be_shown مجازبودن عمومی نمایش بر اساس حالت مستقیم، اتصال یا تنظیم آفلاین، کارت فعال و بدهی سررسیدشده است؛ تضمین وجود کارت مناسب برای مبلغ هر فاکتور نیست. صلاحیت نهایی هر پرداخت در زمان انتخاب و رزرو بررسی میشود. اطلاعات کارت، کلید APK و پیامک خام در این مسیر ارسال نمیشود.
وضعیت حدود هر ۵ ثانیه بررسی، در تغییر ارسال و هنگام سکون حدود هر ۱۵ ثانیه heartbeat فرستاده میشود. تشخیص قطع بدون پیام خروج تابع تازگی آخرین ارتباط دستگاه (حدود ۳۰ ثانیه) و کش کوتاهمدت است؛ این سرویس اتصال لحظهایِ بدون تأخیر را تضمین نمیکند. کلید، مجوز و وضعیت حساب در طول اتصال دوباره کنترل میشوند؛ لغو کلید با کد 1008 اتصال را میبندد. در خطای موقت یا کد 1013 با فاصلهٔ افزایشی و تصادفی دوباره متصل شوید؛ پس از 1008 بدون اصلاح اعتبارنامه تکرار نکنید. شمارهٔ sequence فقط در همان اتصال معتبر است.
client.connection_status()
client.set_offline_card_visibility(True)
# Server-side live example:
# python connection_watch.py
این بسته شامل کلاینت، CLI، سرور وبهوک، README، فایل requirements و نمونه تنظیم متغیرهای محیطی است. کلید و رمز واقعی خود را فقط روی سرور تنظیم کنید.