Skip to content

Integrations

Thin HTTP adapters that read a raw webhook body, call processWebhookHttp, and map inbox outcomes to status codes.

Updated View as Markdown

Framework packages in PayKernel are thin HTTP wrappers around @paykernel/integration-http. They read the raw webhook body, run processWebhookHttp, and return the status from mapInboxOutcome. They do not fulfill orders, pick a store, or put HTTP status codes in @paykernel/webhooks.

All integration packages are publishedintegration-http 0.1.2 and hono/elysia/express/cloudflare-workers 0.1.1 on npm.

Packages

Package Page Role
@paykernel/integration-http HTTP Portable mapping. Owns mapInboxOutcome and processWebhookHttp. Depends on @paykernel/core and @paykernel/webhooks only.
@paykernel/integration-hono Hono honoWebhook. Reads c.req.raw.text(). Peer hono >= 4. Portable.
@paykernel/integration-elysia Elysia elysiaWebhook(path, options) with { parse: "none" }. Peer elysia >= 1. Portable.
@paykernel/integration-express Express expressRawJson() + expressWebhook. Peer express >= 4. Node-only.
@paykernel/integration-cloudflare-workers Cloudflare Workers handleCloudflareWebhook + readWorkerBindings. No cloudflare:workers static import. Portable.

Each framework package depends only on @paykernel/integration-http among workspace packages, and re-exports mapInboxOutcome, processWebhookHttp, requireStringBindings, and the other HTTP helpers so the app can import one package. They do not re-export OBJECT_HMAC_GATEWAYS — import that from @paykernel/integration-http if you need the set.

Request path

HTTP request
  -> framework adapter (raw text / Buffer, never JSON.parse for Stripe)
  -> processWebhookHttp
       1. signature header/query guard (missing required material -> 400, client not called)
       2. engine.processWithVerifier
            verifyAndNormalize: client.handleWebhook (verify + normalize only)
            inbox claim / lease
            handler (fulfill only after claim)
       3. mapInboxOutcome -> status
  -> JSON body { outcome } or { error: "invalid_webhook" }

handleWebhook verifies and normalizes. It does not claim, lease, or set HTTP status. Status codes live in @paykernel/integration-http, not in @paykernel/webhooks.

Raw body before verify

Webhook routes must read the body as text (or Buffer / Uint8Array) before any JSON parser.

Adapter How the body is read
HTTP You pass rawBody: string | Uint8Array. Do not JSON.parse / JSON.stringify Stripe / PayPal / MyFatoorah bytes.
Hono c.req.raw then request.text(). Never c.req.json().
Elysia request.text() on a route registered with { parse: "none" }.
Express expressRawJson() (express.raw({ type: "application/json" })) on the webhook route only.
Workers request.text().

Stripe, PayPal, and MyFatoorah HMAC over the exact raw bytes. Tap, Moyasar, and Paymob HMAC over parsed object fields (OBJECT_HMAC_GATEWAYS in @paykernel/integration-http).

HTTP policy

Default ackPolicy is { kind: "provider_redelivery" }: scheduled_for_retry is 503, not 200. { kind: "durable_worker" } ACKs 200 only for persisted parked / handler_retry when engine.mode === "durable_retry" and workerGuaranteed === true; otherwise processWebhookHttp warns and returns 503. Full table: HTTP mapping.

What these packages are not

  • Not store adapters. Inject a WebhookInboxStore from a @paykernel/store-* package after an explicit migrate. Local SQLite is single-host. :memory: is one process. Memory stores from @paykernel/testkit are NON-PRODUCTION.
  • Not gateway packages. Built-in gateways (stripe, paypal, paymob, moyasar) come from @paykernel/core.
  • They never call createPayment, capture, refund, or fulfillment.
  • They do not implement /internal/* test hooks. Those routes in the examples are unauthenticated (enableTestHooks) and must not be deployed.

Runnable hosts

Thin apps that call these adapters:

See also Getting started and Webhooks.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close