Проверка на Business webhook потписи
Објавено издание: SDK 0.1.3 е јавно достапен на npm. Инсталацијата не активира серверски функции.
Англискиот технички текст подолу е авторитативен за оваа меѓународна Business интеграција. Методите, полињата и безбедносните правила се исти за MK, BA, RS и AL; ова не е Individual MoR. English guide.
Use the Node-only @kordiva/sdk/merchant-webhooks export for Business payment/subscription lifecycle events. It is neither Stripe verification nor the existing P-256 @kordiva/sdk/webhooks agentic contract.
Signature inputs
Дел „Signature inputs“| Header | Meaning |
| --- | --- |
| Kordiva-Webhook-Id | Event UUID, matching the verified body’s id. |
| Kordiva-Webhook-Timestamp | Delivery signing time in Unix seconds. |
| Kordiva-Webhook-Key-Id | Must match your configured credential’s key ID. |
| Kordiva-Webhook-Signature | Versioned HMAC-SHA256 signature. |
Read unchanged raw request bytes. Do not parse JSON and re-stringify it before verification; whitespace, Unicode or key-order changes alter signed bytes. Configure a request/body limit in your HTTP host before buffering. The verifier rejects bodies over 128 KiB, invalid signatures, wrong key IDs, unsupported envelopes and invalid timestamps.
import { verifyMerchantWebhook, type MerchantWebhookEvent,} from "@kordiva/sdk/merchant-webhooks";
export interface MerchantWebhookOptions { secret: string; keyId: string; storeId: string; organizationId: string; environment: "TEST" | "LIVE"; /** Merchant-supplied adapter: atomically insert unique event.id + durable work. * Duplicates must succeed without repeating effects. TEST/test:true is record-only. * This example does not supply a database or grant fulfillment permissions. */ recordEventAndEnqueueOnce: (event: MerchantWebhookEvent) => Promise<void>;}
/** Framework-neutral Node Fetch handler. Set a 128 KiB host body limit BEFORE * buffering. Configure secret/keyId from protected endpoint-specific settings * (for example KORDIVA_WEBHOOK_SECRET / KORDIVA_WEBHOOK_KEY_ID), never the request. */export function createMerchantWebhookHandler(options: MerchantWebhookOptions) { return async function POST(request: Request): Promise<Response> { if (request.method !== "POST") return new Response(null, { status: 405 }); let event: MerchantWebhookEvent; try { const rawBody = new Uint8Array(await request.arrayBuffer()); if (rawBody.byteLength > 128 * 1024) return new Response(null, { status: 413 }); // Verify original bytes, never JSON.parse followed by JSON.stringify. event = verifyMerchantWebhook({ body: rawBody, headers: request.headers, secret: options.secret, keyId: options.keyId, }); } catch { return new Response(null, { status: 400 }); } if ( event.storeId !== options.storeId || event.organizationId !== options.organizationId || event.environment !== options.environment ) return new Response(null, { status: 403 }); try { // Return 2xx only after durable acceptance. Your worker checks event type, // canonical payment state and customer ownership. TEST must never fulfill LIVE. await options.recordEventAndEnqueueOnce(event); } catch { return new Response(null, { status: 503 }); } return new Response(null, { status: 204 }); };}Use the secret/key ID displayed by CMS for this endpoint and environment. Treat verification errors as untrusted input; never log secrets or raw private request data. Do not fetch verification keys from event-supplied URLs.
The default replay window is 300 seconds, with at most 30 seconds of future clock skew. Keep receiver clocks accurate. An optional maxAgeSeconds may narrow the window from 1 to 300, not expand it. This check does not replace persistent event-ID deduplication: retries receive fresh delivery signatures while retaining the same event ID/body.
Fetch API handler pattern
Дел „Fetch API handler pattern“The embedded createMerchantWebhookHandler above illustrates a Node.js Fetch API route (for example a Next.js Node route). Pass the signing secret/key ID and expected tenant/environment from protected server settings. options.recordEventAndEnqueueOnce is your storage adapter, not a Kordiva SDK method. Implement it with an atomic unique event-ID inbox insert and durable work enqueue; duplicate input succeeds without repeating effects. Keep TEST records isolated and never let them trigger LIVE fulfillment. Enforce host-level body limits before this handler runs.
The source-backed handler above is the complete pattern; supply the durable storage adapter described here.
Do not grant access for every verified event indiscriminately. Check the expected type and canonical payment/subscription state, authenticated customer mapping, amount/currency and fulfillment rules in your durable worker. customer.ref maps to your server-owned identity; contact email alone does not authorize access. TEST events must never fulfill real purchases. When state is uncertain or events arrive out of order, reconcile the subscription API or the one-time LIVE payment-confirmation flow.
Acknowledge a duplicate after your storage proves it was durably accepted. Do not rely on memory, timestamps alone or browser state. If processing fails after acknowledgement, your own durable queue must recover it; returning 2xx tells Kordiva acceptance is complete.
Rotation and operations
Дел „Rotation and operations“Rotate key in CMS invalidates the old credential immediately; no overlapping grace is promised. Store the new key ID and secret securely and coordinate the receiver. Do not weaken verification to accept an unknown key or bypass scope checks during rotation. Review CMS setup and delivery behavior for disable/resume, terminal responses and the eight-attempt bound.
Related guides
Дел „Related guides“Business webhooks · Subscriptions · Checkout · Business refunds · Security · API reference