اتصال هویت مشتری
چرا هر جلسه پرداخت مشتری شما را نام میبرد، فرایند اتصال، صف بررسی، و سه اندپوینتی که یک اتصال را مدیریت میکنند
هر جلسه پرداخت متعلق به یکی از مشتریان خود شماست، و کوینلند پی این رابطه را صریح و دائمی میکند:
اولین باری که یکی از مشتریان شما پرداخت کند، حساب کوینلندی که با آن میپردازد به customer.id شما
متصل میشود. از آن پس فقط همان حساب کوینلند میتواند جلسههای آن مشتری را بپردازد، فقط شما
میتوانید این پیوند را قطع کنید، و خود مشتری نمیتواند آن را تغییر دهد.
این یک الزام مبارزه با پولشویی (AML) است، نه یک بهینهسازی. هر پرداخت روی این ریل همیشه به یک مشتری مشخص از یک کسبوکار مشخص قابل ردیابی است، و اتصال همان چیزی است که «همان شخص بودن» را از یک حدس به یک واقعیت تبدیل میکند.
شیء customer
POST /sessions در هر فراخوانی یک شیء customer میخواهد. نه راهی برای انصراف وجود دارد و نه
استثنایی برای هیچ کسبوکاری: فراخوانی ساخت بدون آن با PAY_CUSTOMER_REQUIRED (۴۲۲) رد میشود.
"customer": {
"id": "user-1042",
"name": "Hamid Khosravi",
"native_name": "حمید خسروی",
"email": "hamid@example.com"
}| فیلد | الزامی | محدودیتها | چیست |
|---|---|---|---|
id | بله | [A-Za-z0-9_.:-]، ۱ تا ۱۲۸ | شناسه داخلی خود شما برای این مشتری. اتصال برای همیشه بر پایه آن کلید میخورد، پس باید در سیستم شما پایدار باشد |
name | بله | ۱ تا ۲۵۵ | نام کامل مشتری، به خط لاتین |
native_name | نه، اما بهشدت توصیهشده | ۱ تا ۲۵۵ | نام کامل به خط مادری مشتری. پایه قوی تطبیق نام است، پس هر جا آن را دارید بفرستید |
email | بله | یک ایمیل معتبر | ایمیل مشتری نزد شما. میتواند با ایمیل کوینلند او فرق داشته باشد |
از اینکه این شیء بخشی از قرارداد است، دو قاعده نتیجه میشود:
- هرگز مقدار جایگزین نفرستید. هویتی که میفرستید همان هویتی است که متصل میشود. یک مقدار مثل
"guest"یا"test"یک حساب کوینلند واقعی را برای همیشه به هویت اشتباه گره میزند — آماده انتشار را ببینید. - هویت بخشی از اثر انگشت ایدمپوتنسی است. ارسال دوباره همان
reference_idباcustomerمتفاوتPAY_DUPLICATE_REFERENCE(۴۰۹) میگیرد، دقیقاً همانطور که تغییر مبلغ میگرفت.
فرایند اتصال
اولین باری که یک customer.id مشخص به شما پرداخت کند، ویجت میزبانیشده پیش از آنکه پرداخت جلو برود
یک فرایند اتصال اجرا میکند:
پرداختکننده پیوند را دو بار تأیید میکند. دو تأیید صریح، هر کدام با یک گزینه «خواندم و متوجه شدم»: اینکه حساب کوینلندی که با آن وارد شده متعلق به خود اوست، و اینکه این حساب بهصورت دائمی به این هویت مشتری نزد کسبوکار شما متصل خواهد شد. رضایتِ بیسروصدا وجود ندارد — پرداختکننده نمیتواند حسابی را متصل کند بیآنکه خوانده باشد این کار یعنی چه.
کوینلند نام را بررسی میکند. یک مقایسه فازی میان name و native_nameای که شما فرستادهاید و
نام احرازشده (KYC) روی حساب کوینلند. پایه قوی این بررسی native_name است، و همین است که فرستادنش
ارزش یک ستون اضافه در پایگاه داده شما را دارد.
نتیجه بررسی تعیین میکند بعد چه میشود.
- تطبیق — اتصال
activeمیشود و پرداخت جلو میرود. - عدم تطبیق — اتصال
pending_reviewمیشود: پرداخت رد میشود و اتصال در صف بررسی شما میماند. تأیید شما آن را بدون تکرار فرایند از سوی مشتری فعال میکند؛ رد شما آن را کنار میگذارد.
تکمیل هر پرداخت — چه اولین و چه صدمین — کد دوعاملی (TOTP) پرداختکننده را هم میخواهد، همان سطح
امنیتی یک برداشت. این مرحله کاملاً سمت ویجت است: ویجت ممکن است TOTP_REQUIRED،
TOTP_NOT_ENROLLED یا TOTP_INVALID را به پرداختکننده نشان دهد، و هیچکدام به یکپارچهسازی شما
نمیرسند.
پس از اتصال
وقتی یک اتصال active شد:
- فقط حساب کوینلند متصلشده میتواند جلسههای ساختهشده برای آن
customer.idرا بپردازد. هر حساب دیگری باPAY_BINDING_MISMATCH(۴۰۳) رد میشود. - مشتری هرگز نمیتواند اتصال را تغییر دهد. هیچ گسستن، اتصال دوباره یا انتقالی از سمت مشتری وجود ندارد. فقط شما میتوانید آن را قطع کنید.
- از هر طرف فقط یک اتصال زنده. یک
customer.idکه اتصال زنده دارد نمیتواند حساب دومی را متصل کند، و حساب کوینلندی که به یکی از مشتریان شما متصل است نمیتواند به مشتری دیگری متصل شود — هر دو تلاشPAY_BINDING_CONFLICT(۴۰۹) میگیرند.
هر چه در ادامه میآید زیر کلید پرداختگیری شما اجرا میشود
(Authorization: Bearer clpay_live_…)، همان کلیدی که جلسه میسازد.
خواندن یک اتصال
curl https://my.coinlandexchange.com/api/pay/v1/customers/user-1042/binding \
-H "Authorization: Bearer $COINLAND_PAY_KEY"{
"customer_id": "user-1042",
"state": "active",
"binding": {
"binding_id": "5b8e2f40-7a13-4c96-8d2e-1f6a9c3b70e4",
"customer_id": "user-1042",
"payer_id": "7c1e5b90-3f42-4a86-9d05-2b8e4c1f6a37",
"masked_name": "H**** K****",
"supplied_name": "Hamid Khosravi",
"supplied_name_native": "حمید خسروی",
"supplied_email": "hamid@example.com",
"status": "active",
"match_score": "0.94",
"match_passed": true,
"bound_at": "2026-08-12T10:15:22.000Z",
"reviewed_at": null,
"created_at": "2026-08-12T10:14:03.000Z"
}
}state یکی از سه مقدار است:
state | معنا | binding |
|---|---|---|
none | این customer.id هرگز حسابی متصل نکرده است | null |
active | متصل؛ حساب پیوندخورده میتواند پرداخت کند | شیء اتصال |
pending_review | تطبیق نام ناموفق بود؛ مشتری تا وقتی شما تعیین تکلیف نکنید نمیتواند پرداخت کند | شیء اتصال |
دو فیلد خواندن دقیقی میخواهند:
masked_nameنام احرازشده حساب کوینلند است، ماسکشده ("H**** K****"). API هرگز نام کامل حساب یا ایمیل کوینلند آن را فاش نمیکند — ماسک آنقدر هست که شخصی را که قصدش را داشتید بازبشناسید، و آنقدر نیست که یک غریبه را شناسایی کند.payer_idهمان دستگیره مبهمی است که API پرداخت به مشتری به کار میبرد، پس یک اتصال بدون هیچ جستوجویی آرگومان گیرنده یک پرداخت را به دست شما میدهد.
فیلدهای supplied_name، supplied_name_native و supplied_email همان چیزی را بازتاب میدهند که
شما روی جلسهای که اتصال را ساخت فرستادید — طرفِ شما در مقایسه، در کنار match_score و
match_passed که ثبت میکنند بررسی چطور گذشت.
بررسی یک اتصال در انتظار
اتصال pending_review یعنی یک آدم واقعی خواست پرداخت کند و نتوانست. این اتصال در دو جا در صف بررسی
شما مینشیند: زبانه «مشتریان» کنسول کسبوکار و API زیر — از هر کدام که با کار شما جور است تعیین
تکلیف کنید، نتیجه یکی است.
curl -X POST https://my.coinlandexchange.com/api/pay/v1/customers/user-1042/binding/review \
-H "Authorization: Bearer $COINLAND_PAY_KEY" \
-H "Content-Type: application/json" \
-d '{"action": "approve"}'curl -X POST https://my.coinlandexchange.com/api/pay/v1/customers/user-1042/binding/review \
-H "Authorization: Bearer $COINLAND_PAY_KEY" \
-H "Content-Type: application/json" \
-d '{"action": "reject", "reason": "Name does not match our records"}'فیلد reason برای reject الزامی است و روی اتصال ثبت میشود. پاسخ، اتصالِ بهروزشده است:
{
"binding": {
"binding_id": "5b8e2f40-7a13-4c96-8d2e-1f6a9c3b70e4",
"customer_id": "user-1042",
"status": "active",
"reviewed_at": "2026-08-12T11:02:47.000Z"
}
}- تأیید اتصال را فعال میکند. مشتری فرایند را دوباره اجرا نمیکند — رضایتش را قبلاً داده بود؛ آنچه کم بود تأیید شما بود که ناهمخوانی نام مشکلی ندارد. تلاش بعدی او برای پرداخت انجام میشود.
- رد اتصال را کنار میگذارد. تلاش بعدی آن مشتری برای پرداخت، با هر حسابی که آن موقع وارد شود، یک فرایند تازه را آغاز میکند.
بررسی اتصالی که pending_review نیست PAY_BINDING_STATE (۴۰۹) میگیرد: این عمل فقط در همان یک
وضعیت مجاز است.
بررسی معوق یعنی یک مشتری مسدود، نه یک کار پسزمینه
تا وقتی یک اتصال در pending_review مانده، آن مشتری اصلاً نمیتواند به شما پرداخت کند. وبهوک
binding.review را یک فراخوان به یک انسان بگیرید، نه یک سطر در یک گزارش — پول وقتی میرسد که کسی
تصمیم بگیرد.
قطع یک اتصال
قطع اتصال یعنی این جمله: «این حساب کوینلند دیگر متعلق به این مشتری نیست.»
curl -X DELETE https://my.coinlandexchange.com/api/pay/v1/customers/user-1042/binding \
-H "Authorization: Bearer $COINLAND_PAY_KEY" \
-H "Content-Type: application/json" \
-d '{"reason": "Customer reports the account is no longer theirs"}'{
"customer_id": "user-1042",
"state": "revoked"
}فیلد reason الزامی است: گسستن یک پیوند هویتی یک عمل قابل حسابرسی است، و ثبتِ چرایی کنار ثبتِ چیستی
جا دارد.
عمداً هیچ راهی برای نام بردن یک حساب جانشین در همان فراخوانی وجود ندارد. قطع فقط پیوند را میگسلد و نه بیشتر؛ دفعه بعدی که آن مشتری پرداخت کند یک فرایند تازه اجرا میشود و شخص جدید خودش را همانطور اثبات میکند که نفر اول کرد — رضایت، تطبیق نام، و اگر بررسی ناموفق بود صف بررسی. APIای که اجازه دهد شما مستقیم یک حساب دلخواه را متصل کنید، به یک کلید لورفته اجازه میداد پرداختهای یک مشتری را منحرف کند — دقیقاً همان چیزی که فرایند اتصال برای جلوگیری از آن وجود دارد.
رویدادهای وبهوک
سه رویداد، با همان سازوکار ارسال و امضای بقیه رویدادها، و با همان هشدار: محتوا یک سرنخ
است. پیش از عمل کردن، وضعیت معتبر را از GET /customers/{customer_id}/binding بخوانید.
| نوع | چه زمانی | چه کاری کنید |
|---|---|---|
binding.completed | مشتری متصل شد — فرایند با موفقیت گذشت، یا شما یک بررسی را تأیید کردید | مشتری را در سمت خودتان قابلپرداخت علامت بزنید |
binding.review | تطبیق نام ناموفق بود؛ مشتری تا تأیید یا رد شما نمیتواند پرداخت کند | به یک انسان خبر دهید؛ از کنسول یا اندپوینت بررسی تعیین تکلیف کنید |
binding.revoked | پیوند گسسته شد — یک قطع یا یک رد | منتظر یک فرایند تازه در پرداخت بعدی مشتری باشید |
{
"event_id": "f83a2c16-4d95-4b70-8e21-6c0d9f3a5b48",
"type": "binding.review",
"binding_id": "5b8e2f40-7a13-4c96-8d2e-1f6a9c3b70e4",
"customer_id": "user-1042",
"status": "pending_review"
}هر سه رویداد همین شکل را دارند؛ status روی binding.completed برابر active، روی
binding.review برابر pending_review، و روی binding.revoked برابر revoked است.
خطاها
| کد | HTTP | معنا | چه کاری کنید |
|---|---|---|---|
PAY_CUSTOMER_REQUIRED | ۴۲۲ | POST /sessions بدون شیء customer فراخوانی شد | در هر فراخوانی ساخت، id و name و email را بفرستید. راهی برای انصراف وجود ندارد |
PAY_BINDING_REQUIRED | ۴۰۳ | پرداختکننده پیش از آنکه فرایند او را متصل کند خواست تأیید کند | سمت ویجت است؛ پرداختکننده اول فرایند را کامل میکند. چیزی در کد شما برای اصلاح نیست |
PAY_BINDING_REVIEW | ۴۰۳ | اتصال در انتظار بررسی شماست، پس پرداخت رد میشود | تأیید یا رد کنید — زبانه «مشتریان» کنسول یا اندپوینت بررسی |
PAY_BINDING_MISMATCH | ۴۰۳ | حساب کوینلندی که وارد شده همانی نیست که به این customer.id متصل است | مشتری با حساب متصلشده وارد شود — یا اگر پیوند واقعاً اشتباه است، شما آن را قطع کنید |
PAY_BINDING_CONFLICT | ۴۰۹ | این customer.id یا آن حساب کوینلند همین حالا یک اتصال زنده دارد | اتصال را بخوانید و تصمیم بگیرید؛ اگر پیوند موجود اشتباه است اول قطعش کنید |
PAY_BINDING_STATE | ۴۰۹ | این عمل در وضعیت فعلی اتصال مجاز نیست، مثلاً بررسی یک اتصال فعال | اتصال را بخوانید و بر پایه status شاخه بگذارید |
مرحله تأیید پرداخت ممکن است TOTP_REQUIRED، TOTP_NOT_ENROLLED یا TOTP_INVALID هم پاسخ بدهد —
همان گام دوعاملی که هر پرداختی دارد. اینها داخل ویجت به پرداختکننده نشان داده میشوند و هرگز به
یکپارچهسازی شما نمیرسند.
«مشتری من حساب کوینلندش را عوض کرده»
سؤالی که هر میز پشتیبانی بالاخره میگیرد. پاسخ یک حرکت است: اتصال را قطع کنید، با دلیل، و هیچ
کار دیگری نکنید. دفعه بعد که آن مشتری پرداخت کند، ویجت با هر حسابی که وارد شود یک فرایند تازه اجرا
میکند، تطبیق نام دوباره انجام میشود، و اتصال جدید وضعیت active خود را همانطور به دست میآورد که
قبلی آورده بود.
سعی نکنید با ویرایش رکورد مشتری در سمت خودتان اتصال را «منتقل» کنید: یک customer.id تازه برای همان
شخص، تاریخچه او را در دفترهای شما دوپاره میکند و اتصالِ شناسه قدیمی را زنده باقی میگذارد.
فهرست بررسی
customerدر هر فراخوانی ساخت فرستاده شود، از پایگاه داده مشتریان خودتان، هرگز مقدار جایگزین.- هر جا
native_nameرا دارید بفرستید — تطبیق نام به آن تکیه میکند. customer.idدر تمام عمر مشتری در سیستم شما پایدار بماند.- رویداد
binding.reviewبه یک انسان خبر بدهد؛ کسی مالک صف بررسی باشد. - برای تغییر حساب، تنها ابزار شما قطع اتصال است — قطع کنید و بگذارید فرایند بقیهاش را انجام دهد.