elysiaWebhook(path, options) returns an Elysia instance with POST path registered as { parse: "none" }, then calls processWebhookHttp. No payment logic, no store adapters. Depends only on @paykernel/integration-http among workspace packages.
Version 0.1.1 — published on npm. Portable (paymentsSdk.portable: true). Peer elysia >= 1. Export map: "." only.
bun add @paykernel/integration-elysia
# dependency: @paykernel/integration-http
# peer: elysia >= 1Usage
import { Elysia } from "elysia";
import { elysiaWebhook } from "@paykernel/integration-elysia";
const app = new Elysia()
.use(
elysiaWebhook("/webhooks/stripe", {
gateway: "stripe",
client, // PaymentClient with no onWebhookVerified fulfillment
engine,
handler,
}),
)
.listen(3000);options is Omit<ProcessWebhookHttpInput, "rawBody" | "headers" | "query">.
What the registered handler does:
rawBody = await request.text()headers = request.headers- Query from
new URL(request.url).searchParams(first value per key) processWebhookHttp({ ...options, rawBody, headers, query })return webhookHttpResultToResponse(result)
The route is created with { parse: "none" } so Elysia does not JSON-parse the webhook body.
Runnable host: Bun + Elysia + SQLite. That example’s SQLite is single-host (:memory: is one process).
Failure paths
Same table as processWebhookHttp. Typical Stripe cases:
| Request | Status | Body |
|---|---|---|
Missing stripe-signature |
400 | { error: "invalid_webhook" } — client not called |
| Forgery (bad HMAC) | 400 | { error: "invalid_webhook" } |
Parse / missing-config InvalidWebhookError |
500 | { outcome: "handler_failed", retryable: true } |
already_processing |
503 | { outcome: "already_processing" }; Retry-After when retryAfterMs is set |
payload_conflict |
409 | { outcome: "payload_conflict" } |
| Handler throws | 500 | { outcome: "handler_failed", retryable: true } |
Default ackPolicy is provider_redelivery (scheduled_for_retry → 503). { kind: "durable_worker" } is valid only with engine.mode === "durable_retry" and workerGuaranteed === true; otherwise processWebhookHttp warns and returns 503.
Status codes come from mapInboxOutcome in @paykernel/integration-http, not from @paykernel/webhooks.
Paymob query signatures work because the adapter forwards URL.searchParams as query.
Re-exports
import {
elysiaWebhook,
mapInboxOutcome,
retryAfterSeconds,
processWebhookHttp,
webhookHttpResultToResponse,
createWebhookOperationContext,
getHeader,
resolveCorrelationId,
requireStringBindings,
GATEWAY_WEBHOOK_SIGNATURE,
extractWebhookSignature,
} from "@paykernel/integration-elysia";Types re-exported: InboxHttpAckPolicy, HeaderBag, GatewayWebhookSignatureProfile, WebhookClient, WebhookHttpResult, ProcessWebhookHttpInput.
OBJECT_HMAC_GATEWAYS is not re-exported here. Import it from @paykernel/integration-http.
Example POST /internal/* routes in the Elysia checkout example are unauthenticated test hooks (enableTestHooks) and must not be deployed.