Skip to content

Webhooks

Billing events are POSTed to your endpoint with HMAC header x-autlantic-signature.

Verify

ts
import {
  verifyBillingWebhook,
  parseBillingWebhookEvent,
  BILLING_WEBHOOK_SIGNATURE_HEADER,
  type BillingWebhookEvent,
} from "@autlantic/payments-recurring";

const signatureHeader = req.headers[BILLING_WEBHOOK_SIGNATURE_HEADER]; // x-autlantic-signature
const ok = verifyBillingWebhook(
  rawBody,
  signatureHeader,
  process.env.AUTLANTIC_BILLING_WEBHOOK_SECRET!,
);
if (!ok) throw new Error("bad signature");

const event: BillingWebhookEvent = parseBillingWebhookEvent(JSON.parse(rawBody));

Always verify against the raw request body. Do not re-serialize JSON before checking the signature.

Event types

ts
type BillingWebhookEvent = {
  type: BillingWebhookEventType;
  id: string;
  createdAt: string;
  data: Record<string, unknown>;
};
EventWhen
subscription.createdSubscription created (incomplete)
subscription.activatedMandate completed / subscription became active
subscription.updatedAmount, interval, plan, or metadata changed
subscription.past_dueAutomatic retries exhausted
subscription.canceledSubscription canceled
invoice.createdInvoice opened (first or renewal)
invoice.paidCharge succeeded
invoice.payment_failedCharge failed; see data.failureCode / errors
invoice.refundedRefund recorded
invoice.voidedOpen invoice voided
payment.createdOne-time payment created (open)
payment.paidOne-time payment confirmed

How these line up on a real checkout: Lifecycle. Also see One-time payments.

Signing (outbound tests)

ts
import { signBillingWebhook } from "@autlantic/payments-recurring";

const signature = signBillingWebhook(rawBody, process.env.AUTLANTIC_BILLING_WEBHOOK_SECRET!);

Env

VariablePurpose
AUTLANTIC_BILLING_WEBHOOK_SECRETShared HMAC secret
AUTLANTIC_BILLING_WEBHOOK_URLDestination URL for delivered events (hosted API / worker)

Autlantic Payments SDK