- خانه
- وبهوک و idempotency
راهنماها
وبهوک و idempotency
در UnoPay 1.0.0 هیچ API وبهوکی وجود ندارد. هر کالبک همان ریدایرکت مرورگر است — یعنی تکرار، مسابقه، و پرداختکنندهای که تب را قبل از اجرا میبندد.
کالبک ریدایرکت در برابر وبهوک
| جنبه | کالبک ریدایرکت (آنچه UnoPay انجام میدهد) | وبهوک سرور به سرور |
|---|---|---|
| Delivered by | The payer's browser | The gateway's servers |
| Reliable | No. A closed tab loses it permanently. | Retryable, with an acknowledgement contract |
| Duplicates | Common — refresh, back button, prefetch | Expected — at-least-once delivery |
| Amount source | Your callback request, which you control | The gateway's payload |
| In UnoPay 1.0.0 | Supported | No API. Nothing in the SDK calls your server. |
مغایرتگیری اختیاری نیست
چون پرداختکننده کالبک را میراند، بعضی پرداختها هرگز به شما زنگ نمیزنند. هیچ تنظیمی در UnoPay این را تغییر نمیدهد. دو راهکار، هر دو لازم:
- انقضای پرداختهای کهنه. کاری زمانبندیشده که
pendingرا بهexpiredمیبرد و نگهداشتن سفارش را آزاد میکند، با بهروزرسانی شرطی تا کالبک دیرهنگام بازنویسی نشود. - مغایرتگیری با گزارش درگاه طبق سند تسویه خود بانک. هیچچیز در SDK این را انجام نمیدهد و هیچ API از UnoPay آن را در اختیار نمیگذارد.
تغییر حالت را idempotent کنید
زرینپال وقتی همان آتوریتی دوباره وریفای شود 101 میدهد و آداپتور آن را به isSuccessful: true نگاشت میکند. پس هر کالبک تکراری هر بار یک وریفای موفق تولید میکند. درگاه idempotent است؛ نوشتن پایگاه داده شما هم باید باشد.
// Idempotency lives in the WHERE clause, not in application logic.
export async function confirmPayment(authority: string, refId: string) {
const { count } = await db.payments.updateMany({
where: {
authority,
state: { in: ['pending', 'expired'] }, // already 'paid' matches nothing
},
data: { state: 'paid', refId, settledAt: new Date() },
});
if (count === 0) return false; // a duplicate; the first call already won
// Only the transition that actually changed the row may fulfil the order.
await fulfilOrderFor(authority);
return true;
}
// And a uniqueness constraint is still the backstop:
// UNIQUE (authority)
// UNIQUE (refId)
verifyCallback را خودکار تلاش مجدد نکنید
وریفای تکراری یک فراخوانی واقعی دوم به درگاه است و دوباره بودجه ۱۰ ثانیهای را مصرف میکند. تلاش مجدد خوب است؛ تلاش مجدد داخل هندلر کالبک با زمانبندی کوتاه پلتفرم خوب نیست. یک وضعیت قابل تلاش مجدد برگردانید و بگذارید صف خودتان مدیریتش کند.
چه چیزی به مرورگر پرداختکننده برگردانیم
یک صفحه واقعی برگردانید، نه یک رشته خام، و اندپوینت را ایمن برای فراخوانی تکراری نگه دارید. حلقه بیپایان ریدایرکت به خود اندپوینت کالبک، نشانه کلاسیک هندلری است که idempotent نیست.
// 200 on success even when this is a duplicate, so the payer's browser
// stops retrying. Use 4xx/5xx only to signal a real, actionable fault.
return new Response(renderResultPage({ ok: result.isSuccessful, ref: result.transactionId }), {
status: result.isSuccessful ? 200 : 400,
headers: { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-store' },
});