Files
skills/docs/api-stack/api/api-plugin-payment/src/schemas/routes/webhook.md
2026-05-29 08:20:56 +01:00

2.0 KiB

webhook

Purpose

Response schema for POST /payments/webhook. The webhook receiver MUST read the raw request body and verify the provider HMAC BEFORE deserialising — there's no body schema because the route does not parse JSON at the Zod boundary; instead the receiver hands the raw bytes to WebhookVerifier.verify from @suaveplan/payment.

The response is intentionally minimal: an accepted: boolean flag the provider's webhook delivery infrastructure can use to decide whether to retry. A true response means "we received and authenticated the payload"; a false response (returned from the rejection path) indicates the request was rejected for a non-retryable reason (signature mismatch) and the provider should not retry.

Features

  • WebhookResponseSchema carries one field: accepted: boolean.
  • Schema is small by design — the wire surface for webhooks is the request body (provider-defined), not the response.

Usage: Basic

import { WebhookResponseSchema } from "@suaveplan/api-plugin-payment/schemas/routes";

const wire = WebhookResponseSchema.parse({ accepted: true });

Usage: Advanced

// Provider-side delivery loop:
const res = await fetch(`${endpoint}/payments/webhook`, {
    method: "POST",
    headers: { "X-Signature": sig, "X-Timestamp": String(ts) },
    body,
});
const { accepted } = WebhookResponseSchema.parse(await res.json());
if (!accepted) {
    // signature failure — do NOT retry, alert on dashboard instead
    alertOps({ event: "webhook_rejected" });
}

API Reference

  • WebhookResponseSchema — z.object({ accepted: z.boolean() }).
  • WebhookResponse — inferred TS type.

Implementation Notes

The receiver does not surface the verified payload back to the provider in the response — payment providers neither inspect nor care about the response body beyond the status code. Returning a minimal { accepted } shape lets operators distinguish authenticated-rejected (200 { accepted: false }) from total-failure (5xx) in their delivery logs without leaking sensitive internal state.