Kखर्चाई
सबै लेखहरू

खर्चाई वेबहुक कसरी बनाउने र प्रमाणित गर्ने

July 12, 2026

खर्चाई वेबहुकले घटना भएकै क्षण तपाईंको सर्भरमा पठाउँछ, त्यसैले परिवर्तनका लागि API लाई बारम्बार जाँच्नुपर्दैन। यो गाइडले दुवै पाटो समेट्छ: ड्यासबोर्डबाट एन्डपोइन्ट सेटअप गर्ने, र त्यहाँ आइपुग्ने कुरामाथि भरोसा गर्न तपाईंको आफ्नो कोडमा चाहिने काम।

आवश्यक कुरा

वेबहुक प्रो र कस्टम योजनामा उपलब्ध छ। सुरु गर्नुअघि थाहा पाउनुपर्ने एउटा कुरा: वेबहुक एन्डपोइन्ट तपाईंको आफ्नै लगइन सेसनमुनि ड्यासबोर्डबाटै मात्र बनाउन, सम्पादन गर्न, वा घुमाउन मिल्छ। API कुञ्जीले यो सतहलाई कहिल्यै छुन पाउँदैन, सबै स्कोप भएको कुञ्जीले पनि। यो जानाजान हो: कुनै कुञ्जी चुहियो भने, त्यसले मात्रै कुनै सुन्ने एन्डपोइन्ट थपेर खर्च र भुक्तानी डेटा पाउन सक्नु हुँदैन।

सन्दर्भ: घटना प्रकार

घटना उपलब्ध
expense.submitted प्रो, कस्टम
expense.approved प्रो, कस्टम
expense.rejected प्रो, कस्टम
payment.processed प्रो, कस्टम
payment.failed प्रो, कस्टम
approval.requested कस्टम
fiscal_year.activated कस्टम

चरण १: एन्डपोइन्ट बनाउनुहोस्

ड्यासबोर्डमा Settings, अनि Webhooks मा जानुहोस्, र तीनवटा कुरासहित एन्डपोइन्ट थप्नुहोस्: नाम, URL, र सदस्यता लिने घटनाहरू। URL HTTPS नै हुनुपर्छ। सेभ गर्दा, खर्चाईले whsec_ बाट सुरु हुने साइनिङ सिक्रेट देखाउँछ। अहिल्यै कपी गर्नुहोस्: यो ठ्याक्कै एक पटक मात्र देखिन्छ र हाम्रो तर्फबाट इन्क्रिप्ट गरी भण्डारण हुन्छ, त्यसैले हराए भने नयाँमा घुमाउनुबाहेक अर्को उपाय हुँदैन।

चरण २: के आउँछ भन्ने थाहा पाउनुहोस्

हरेक डेलिभरी यस्तो आकारको JSON बडीसहितको HTTP POST हो:

{
  "id": "evt_5f2c9a1b3d4e4f2a8b6c7d9e0f1a2b3c",
  "event": "expense.approved",
  "apiVersion": "v1-2026/07/08",
  "createdAt": "2026-07-12T09:14:02.000Z",
  "organizationId": 481,
  "branchId": 12,
  "data": { }
}

apiVersion ले payload को contract चिन्ह्याउँछ। data को आकार बदलिएको बेला मात्र यो बदलिन्छ, त्यसैले माइग्रेसनको बेला दुई contract संस्करण एकैसाथ धान्नुपर्यो भने यसैअनुसार शाखा छुट्याउन मिल्छ।

Content-Type जस्ता सामान्य हेडरमाथि, हरेक डेलिभरीसँग खर्चाई-विशिष्ट तीनवटा हेडर आउँछन्:

  • X-Kharchai-Event: event फिल्डकै मान, त्यसैले बडी पार्स नगरी नै रुट गर्न मिल्छ
  • X-Kharchai-Delivery: यही विशेष डेलिभरी प्रयासको एउटा अद्वितीय ID
  • X-Kharchai-Signature: t=<unix timestamp>,v1=<hex HMAC>

चरण ३: सिग्नेचर प्रमाणित गर्नुहोस्

सिग्नेचर भनेको तपाईंको whsec_ सिक्रेटले साइन गरिएको, hex encode गरिएको, {timestamp}.{raw body} स्ट्रिङको HMAC-SHA256 हो। Node.js मा पूरा जाँच यस्तो हुन्छ:

const crypto = require("crypto");

function isValidKharchaiSignature(secret, signatureHeader, rawBody, toleranceSeconds = 300) {
  const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
  const timestamp = Number(parts.t);
  if (!parts.v1 || !Number.isFinite(timestamp)) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  const sameLength = expected.length === parts.v1.length;
  const matches = sameLength && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
  const fresh = Math.abs(Date.now() / 1000 - timestamp) <= toleranceSeconds;

  return matches && fresh;
}

देखिनुभन्दा बढी महत्त्वपूर्ण दुई कुरा:

rawBody तपाईंले पाएकै ठ्याक्कै बाइट हुनुपर्छ, तपाईंको फ्रेमवर्कले त्यसलाई object मा पार्स गर्नुअघि। JSON.stringify(JSON.parse(rawBody)) माथि सिग्नेचर हिसाब गर्नुभयो भने, key क्रम वा whitespace को फरकले hash नै बदलिन्छ र हरेक डेलिभरी अमान्य देखिन्छ। यसले पहिलो पटक झन्डै सबैलाई अलमल्याउँछ: हाम्रो आफ्नै worker ले पनि ठ्याक्कै यही कारणले पठाउने स्ट्रिङमै साइन गर्छ, फेरि सिरियलाइज गरिएको प्रतिलिपिमा होइन।

साधारण equality जाँचको सट्टा crypto.timingSafeEqual प्रयोग गर्नु किन महत्त्वपूर्ण छ भने, साधारण स्ट्रिङ तुलना पहिलो नमिलेको क्यारेक्टरमै रोकिन्छ, र प्रतिक्रिया समय राम्रोसँग नाप्न सक्ने आक्रमणकारीले त्यसैबाट मान्य सिग्नेचर एक-एक क्यारेक्टर गरी अनुमान लगाउन सक्छ। यसलाई सही गर्न केही पनि खर्च लाग्दैन।

Timestamp माथिको tolerance जाँच replay विरुद्धको तपाईंको सुरक्षा हो: यो नभए, कुनै एक पटक मान्य साइन गरिएको अनुरोध कसैले जहाँबाट भए पनि समात्यो भने, चाहे compromised logging tool बाट होस्, गलत कन्फिगर गरिएको proxy बाट होस्, वा खुला browser devtools बाट, त्यसले त्यसलाई जहिल्यै नयाँ भनी फेरि-फेरि पठाउन सक्छ र तपाईंको सर्भरले हरेक पटक नयाँ भनी स्वीकार गर्छ। पाँच मिनेट एउटा उचित default हो।

चरण ४: रिट्राईलाई idempotent तरिकाले सम्हाल्नुहोस्

असफल डेलिभरी स्वतः exponential backoff सहित पुनः प्रयास हुन्छ, जम्मा ८ प्रयाससम्म, लगभग २, ४, ८, १६, ३२, ६४, र १२८ मिनेटको फरकमा, त्यसपछि हामी हार मानेर dead lettered चिन्ह लगाउँछौं। 200 देखि 299 बाहेकको जुनसुकै प्रतिक्रिया असफलता मानिन्छ र पुनः प्रयास सुरु गराउँछ, redirect सहित, त्यसैले तपाईंको एन्डपोइन्टले अन्तै redirect नगरी सिधै 200 फर्काउने कुरा सुनिश्चित गर्नुहोस्।

यसको मतलब तपाईंको ह्यान्डलरले उही घटना एकपटकभन्दा बढी पाउन सक्छ, जस्तै तपाईंको सर्भरले अनुरोध स्वीकार गरेपछि आफ्नै प्रशोधन नसकिँदै क्र्यास भयो भने। envelope भित्रको id फिल्ड, वा X-Kharchai-Delivery हेडरलाई idempotency key का रूपमा प्रयोग गर्नुहोस्: साइड-इफेक्ट भएको कुनै काम गर्नुअघि processed flag विरुद्ध यो भण्डारण गर्नुहोस्, र पहिल्यै देखिसकेको कुनै पनि कुरा छाड्नुहोस्।

यसको अर्को पाटो गति हो। हामी १० सेकेन्डपछि डेलिभरी प्रयास timeout गर्छौं, त्यसैले टिकाउ गरी क्यु गरेकै क्षण 200 पठाएर स्वीकृति दिनुहोस्, र वास्तविक काम त्यसपछि asynchronously गर्नुहोस्। त्योभन्दा बढी समय लिने ढिलो synchronous ह्यान्डलर हाम्रो तर्फबाट असफलता जस्तै देखिन्छ र पुनः प्रयास हुन्छ, तपाईंको सर्भरले वास्तवमै पाइसके पनि।

समस्या समाधान

हरेक वेबहुक एन्डपोइन्टको ड्यासबोर्डमा डेलिभरी लग हुन्छ: हरेक प्रयास, त्यसको HTTP स्थिति, प्रतिक्रिया बडीको एक अंश, र अर्को पुनः प्रयास कहिले तोकिएको छ। नयाँ इन्टिग्रेसन डिबग गर्दै हुनुहुन्छ भने, पहिले Test बटन प्रयोग गर्नुहोस्। यसले वास्तविक खर्च वा भुक्तानी चाहिनुबिनै, वास्तविक घटनाकै उस्तै साइनिङ र डेलिभरी मार्गबाटै एउटा synthetic ping घटना पठाउँछ।

थाहा पाउनुपर्ने अर्को कुरा: कुनै एन्डपोइन्ट लगातार पाँच डेलिभरीमा असफल भयो भने, खर्चाईले त्यसलाई स्वतः निष्क्रिय गर्छ र तपाईंको संगठनका एडमिनहरूलाई इमेल पठाउँछ, त्यसैले बिग्रिएको इन्टिग्रेसनले महिनौंसम्म छुटेका घटना चुपचाप थुपार्न सक्दैन। एन्डपोइन्ट मिलाएर उही settings पृष्ठबाट फेरि सक्रिय गर्नुहोस्, डेलिभरी फेरि सुरु हुन्छ।

आफ्नो कम्पनीको खर्च नियन्त्रणमा ल्याउन तयार हुनुहुन्छ?

प्रतीक्षा सूचीमा सामेल हुनुहोस्
खर्चाई वेबहुक कसरी बनाउने र प्रमाणित गर्ने | खर्चाई