UnoPayv1.0.0
  1. خانه
  2. وب‌هوک و 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 است؛ نوشتن پایگاه داده شما هم باید باشد.

idempotent.ts ts
// 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 نیست.

result.ts ts
// 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' },
});