مواد پر جائیں
4 ستمبر 2026 · ادائیگیاں

تجزیہ: ایک Stripe ویب ہک پے لوڈ، فیلڈ بہ فیلڈ

یہ مضمون اشاعت کے وقت پروڈکٹ کو بیان کرتا ہے۔ موجودہ صلاحیات کے لیے AI Builder اور Agent Teams دیکھیں۔

تجزیہ: ایک Stripe ویب ہک پے لوڈ، فیلڈ بہ فیلڈ

یہ ایک ویب ہک پے لوڈ ہے جو Stripe نے واقعی بھیجا تھا، تراشا اور خفیہ ڈیٹا ہٹایا گیا ہے مگر ساختی طور پر جوں کا توں — checkout.session.completed ایونٹ، وہی جو تب فائر ہوتا ہے جب کوئی Checkout صفحے پر ادائیگی مکمل کرتا ہے۔ زیادہ تر ڈویلپرز اسے ایک نظر دیکھتے ہیں، data.object.customer اور data.object.amount_totalلے لیتے ہیں، اور آگے بڑھ جاتے ہیں۔ ڈیمو کے لیے یہ عموماً ٹھیک ہوتا ہے۔ لیکن یہی وجہ ہے کہ ایپس آرڈرز کو دوہرا فُل فِل کرتی ہیں، سبسکرپشن تجدیدات چھوٹ جاتی ہیں، اور انہیں ریفنڈ کے بارے میں پہلی ناراض سپورٹ ای میل ملتی ہے جو "مکمل نہیں ہوئی" ہوتی ہے۔ آئیے پورا معاملہ الگ الگ کر کے دیکھتے ہیں۔

{
  "id": "evt_1P8xQ2K7z3n9lWqA00Ff2gLm",
  "object": "event",
  "api_version": "2024-06-20",
  "created": 1725456000,
  "type": "checkout.session.completed",
  "livemode": true,
  "pending_webhooks": 1,
  "request": { "id": "req_9F2mA1", "idempotency_key": null },
  "data": {
    "object": {
      "id": "cs_live_a1B2c3D4",
      "object": "checkout.session",
      "customer": "cus_Q3fZ8xLmN2",
      "customer_details": {
        "email": "[email protected]",
        "tax_ids": []
      },
      "payment_status": "paid",
      "payment_intent": "pi_3P8xQ2K7z3n9lWqA1gH4iJ5k",
      "subscription": "sub_1P8xQaK7z3n9lWqA",
      "amount_total": 2900,
      "currency": "usd",
      "metadata": {
        "app_user_id": "usr_38821",
        "plan": "pro_monthly"
      }
    }
  }
}

id اور idempotency کا مسئلہ جو آپ کو مفت میں ملتا ہے

evt_1P8xQ2K7z3n9lWqA00Ff2gLm شور لگتا ہے جب تک آپ کو احساس نہیں ہوتا کہ یہ واحد چیز ہے جو آپ اور ایک ڈپلیکیٹ آرڈر کے درمیان کھڑی ہے۔ Stripe ویب ہکس بھیجتا ہے کم از کم ایک بار، بالکل ایک بار نہیں۔ اگر آپ کا سرور درخواست قبول کرتا ہے مگر 200 واپس بھیجنے سے پہلے ٹائم آؤٹ ہو جاتا ہے، تو Stripe اسے ناکامی سمجھتا ہے اور وہی ایونٹ دوبارہ بھیجتا ہے، وہی id، کبھی منٹوں بعد، کبھی اگلے دن۔ اگر آپ کا ہینڈلر ہر بار جب یہ دیکھتا ہے کہ سبسکرپشن دیتا ہے checkout.session.completed یہ چیک کیے بغیر کہ کیا یہ اس عین idپر پہلے ہی کارروائی کر چکا ہے، آپ بالآخر اسے دو بار دیں گے۔ حل آپ کے ڈیٹابیس میں ایک لائن ہے: اس فیلڈ پر ایک منفرد قید processed_webhook_events ٹیبل پر، جسے آپ کچھ بھی کرنے سے پہلے چیک کریں۔ یہ پوری انٹیگریشن کی سب سے کم دلچسپ لائن ہے اور وہی جو واقعی اہم ہے۔

وہ signature header جو body میں بالکل نہیں ہوتا

اوپر دیا گیا پے لوڈ وہی ہے جو Stripe درخواست کے باڈی کے طور پر بھیجتا ہے۔ جو یہ نہیں دکھاتا وہ ہے Stripe-Signature ہیڈر جو اس کے ساتھ آتا ہے — ایک ٹائم اسٹیمپ اور آپ کی ویب ہک سائننگ سیکرٹ کے ساتھ کمپیوٹ کیا گیا HMAC-SHA256 دستخط۔ اسے تصدیق کرنا چھوڑ دیں تو آپ کا ویب ہک اینڈ پوائنٹ ایک عوامی POST روٹ بن جاتا ہے جسے انٹرنیٹ پر کوئی بھی خود ساختہ "payment succeeded" JSON بھیج کر آپ کا پیڈ ٹیئر مفت میں کھول سکتا ہے۔ یہ کوئی نظریاتی حملہ نہیں؛ اینڈ پوائنٹ URLs کلائنٹ سائیڈ JS، لاگز، Slack پیسٹس میں لیک ہوتے ہیں، اور اسکینرز بالکل اسی طرح کے روٹ ڈھونڈتے ہیں۔

میں نے یہ عین بگ پروڈکشن میں دو بار دیکھا ہے — دونوں مرتبہ حل صرف پانچ منٹ کا تھا، اور دونوں مرتبہ یہ مہینوں سے لائیو تھا اس سے پہلے کہ کسی نے ڈیٹابیس میں مفت "pro" اکاؤنٹس کو نوٹس کیا۔

تصدیق کرنا آپ کو Stripe کے SDK کے ساتھ صرف تین لائنیں لیتا ہے (stripe.webhooks.constructEvent(body, sig, secret)) اور اسے خام، غیر پارس شدہ درخواست باڈی پر چلنا ضروری ہے — اگر کسی فریم ورک کے JSON middleware نے اسے آپ کے ہینڈلر تک پہنچنے سے پہلے ہی ایک آبجیکٹ میں پارس کر دیا ہے، تو سگنیچر چیک بائٹ بہ بائٹ عدم مطابقت پر ناکام ہو جاتا ہے جس کا کسی حقیقی حملے سے کوئی تعلق نہیں۔ یہ Stripe کے اپنے فورمز پر رپورٹ ہونے والا سب سے عام "میرا ویب ہک ہمیشہ 400 کیوں دیتا ہے" بگ ہے۔

data.object.customer بمقابلہ data.object.customer_details

یہ فالتو لگتے ہیں مگر ہیں نہیں۔ customer Stripe کسٹمر ID ہے — مستحکم، دوبارہ قابل استعمال، وہ چیز جسے آپ فارن کی کے طور پر محفوظ کرتے ہیں۔ customer_details اس لمحے چیک آؤٹ فارم میں خریدار نے جو ٹائپ کیا تھا اس کا اسنیپ شاٹ ہے — ای میل، ٹیکس ID، کبھی نام — اور یہ اس وقت بھی موجود ہو سکتا ہے جب customer null ہو، جو یک بارگی Checkout سیشنز میں ہوتا ہے جہاں آپ نے Stripe سے Customer آبجیکٹ بنانے کے لیے نہیں کہا۔ اگر آپ کا آن بورڈنگ لاجک customer کو ہمیشہ موجود سمجھ کر پڑھتا ہے، تو گیسٹ چیک آؤٹس خاموشی سے اسے توڑ دیتے ہیں۔

metadata: وہ دو فیلڈز جو آپ نے خود ہی وہاں رکھی تھیں

app_user_id اور plan Stripe کی فیلڈز نہیں ہیں — یہ وہی ہیں جو آپ نے Checkout سیشن بناتے وقت اٹیچ کی تھیں۔ یہ پوری انٹیگریشن کا سب سے اہم ڈیزائن فیصلہ ہے اور اسے چھوڑنا آسان ہے کیونکہ Stripe کا quickstart اس پر زیادہ توجہ نہیں دیتا۔ آپ کے اپنے یوزر ID کے بغیر metadataمیں، اس ادائیگی کو آپ کے ڈیٹابیس کی کسی قطار سے جوڑنے کا واحد طریقہ ای میل ملانا ہے، اور ای میلز بدل جاتی ہیں، غلط ٹائپ ہو جاتی ہیں، یا کسی ٹیم ممبر کی جانب سے ادائیگی کرنے والے کسی کی ہوتی ہیں۔ ہر وہ ویب ہک ہینڈلر جو میں نے برا لکھا تھا، بعد میں دیکھا تو، وہ تھا جو شناخت کو دوبارہ تعمیر کرنے کی کوشش کرتا تھا customer_details.email سے، بجائے اس کے کہ اپنی ہی سیٹ کی گئی metadata پر بھروسہ کرے جو تین قدم پہلے موجود تھی۔

payment_status: صرف paid ہی واحد ویلیو نہیں ہے

اس ایونٹ کے محض موجود ہونے کو ادائیگی کا ثبوت سمجھنا آسان ہے۔ یہ ہمیشہ ایسا نہیں ہوتا — payment_status یہ بھی ہو سکتا ہے unpaid (سیشن مکمل ہو گیا مگر بینک ڈیبٹ جیسا تاخیری ادائیگی کا طریقہ ابھی کلیئر نہیں ہوا) یا no_payment_required (مکمل ڈسکاؤنٹ والا چیک آؤٹ، بغیر کارڈ چارج کے فری ٹرائل)۔ اس فیلڈ کو چیک کیے بغیر checkout.session.completed پر فُل فِل کرنے کا مطلب ہے پیسے کی تصدیق ہونے سے پہلے پروڈکٹ بھیج دینا۔ چند ڈالر سے زیادہ کی کسی بھی چیز کے لیے، انتظار کریں payment_status: "paid" کا یا بہتر ہے، فُل فِل مینٹ کو اس کی بنیاد پر کریں invoice.paid / payment_intent.succeeded بجائے سیشن ایونٹ کے۔

ایونٹ کی قسمکب فائر ہوتا ہےاس کے ساتھ کیا کرنا چاہیے
checkout.session.completedخریدار Checkout فارم مکمل کرتا ہےاسے لاگ کریں، مگر تصدیق کریں payment_status فُل فِل کرنے سے پہلے
payment_intent.succeededرقم واقعی کلیئر ہو جاتی ہےیک بارگی خریداری کی تکمیل کے لیے محفوظ پوائنٹ
invoice.paidسبسکرپشن انوائس ادا کر دیا گیا (ابتدائی یا تجدید)رسائی کو بڑھائیں، استعمال کے کاؤنٹرز ری سیٹ کریں
customer.subscription.updatedپلان تبدیل، مقدار تبدیل، cancel-at-period-end آن/آفاہلیت (entitlements) کو سِنک کریں، یہ نہ سمجھیں کہ اس کا مطلب منسوخی ہے
charge.refundedآپ یا خریدار کا بینک چارج واپس کر دیتا ہےرسائی منسوخ کریں، یہی سب سے زیادہ بھلا دیا جاتا ہے

وہ فیلڈ جو اس پے لوڈ میں نہیں ہے: آگے کیا ہوتا ہے

اس JSON میں کچھ بھی یہ نہیں بتاتا کہ Stripe ناکام ڈیلیوری کو بیک آف شیڈول پر تین دن تک دوبارہ کوشش کرے گا، یا مسلسل ناکامیوں کے بعد یہ آپ کے اینڈ پوائنٹ کو غیر فعال کر کے آپ کو ای میل کرے گا۔ یہ رویہ آپ کے Dashboard سیٹنگز میں موجود ہے، پے لوڈ میں نہیں، اور یہی وہ حصہ ہے جسے زیادہ تر ڈویلپرز تب دریافت کرتے ہیں جب ان کا اینڈ پوائنٹ خاموشی سے ایک ہفتے سے مردہ پڑا ہوتا ہے کیونکہ ایک ڈیپلائے نے روٹ پاتھ بدل دیا تھا۔

72 گھنٹے
Stripe ناکام ویب ہک کو ہار ماننے سے پہلے کتنی دیر تک دوبارہ کوشش کرتا رہتا ہے

اپنے ویب ہک اینڈ پوائنٹ کی کامیابی کی شرح پر مانیٹرنگ چیک اسی دن لگائیں جس دن اسے وائر کریں، پہلی چھوٹ جانے والی تجدید کے بعد نہیں۔ پے لوڈ آپ کو بتاتا ہے کہ کیا ہوا۔ یہ آپ کو خبردار نہیں کرتا جب آپ کا ہینڈلر خاموشی سے سننا بند کر دیتا ہے۔

ادائیگیاں
شیئر کریںXLinkedInFacebookRedditQuoraWhatsAppTelegramای میل
← تمام پوسٹس