Payment processing with Stripe and Square.
A provider-agnostic payment interface with adapters for Stripe and Square. Handles checkout sessions, webhook verification, refunds, and idempotent payment processing.
Provider Interface
PaymentProvider defines the common contract:
- Create single and multi-event checkout sessions
- Verify webhook signatures
- Retrieve session details and process refunds
Error subclass for user-facing payment validation errors (e.g. invalid phone number). These propagate through safeAsync so the message can be shown to the user.
Build checkout metadata from a CheckoutIntent (converts items to compact form).
Build checkout session metadata from booking data (items already compact).
Create a withClient helper that runs an operation with a lazily-resolved client. Returns null if the client is not available or the operation fails.
Enforce metadata value length limits for a payment provider.
Extract a human-readable message from an unknown caught value
Normalize validated session metadata into the canonical SessionMetadata shape.
Resolve the active payment provider based on admin settings. Lazy-loads the provider module to avoid importing unused SDKs. Returns null if no provider is configured.
Validate that session metadata contains required fields (name + items).
Type guard: check if a string is a valid PaymentStatus
Safely execute async operation, returning null on error. Re-throws PaymentUserError so user-facing messages propagate.
Convert single-event answerIds to the per-event format used in metadata
Convert registration line items to compact booking items
Convert a provider-specific checkout result to a CheckoutSessionResult. Returns null if session ID or URL is missing.
Wrap a checkout operation, converting PaymentUserError to { error } result and swallowing unexpected errors as null. Used by both provider adapters.
Payment provider interface.
-
checkoutCompletedEventType: string
The webhook event type name that indicates a completed checkout
-
createCheckoutSession(): Promise<CheckoutSessionResult>intent: CheckoutIntent,baseUrl: string
Create a checkout session for one or more events. Returns a session ID and hosted checkout URL, or null on failure.
-
isPaymentRefunded(paymentReference: string): Promise<boolean>
Check if a payment has been refunded via the provider API. Used to refresh refund status from the edit attendee page.
-
refundPayment(paymentReference: string): Promise<boolean>
Refund a completed payment.
-
resolveWebhookSession(event: WebhookEvent): Promise<ValidatedPaymentSession | "skip" | null>
Resolve a validated session from a webhook event. Each provider knows how to extract/fetch session data from its own event structure, so the webhook handler stays provider-agnostic.
-
retrieveSession(sessionId: string): Promise<ValidatedPaymentSession | null>
Retrieve and validate a completed checkout session by ID. Returns the validated session or null if not found / invalid.
-
setupWebhookEndpoint(): Promise<WebhookSetupResult>secretKey: string,webhookUrl: string,existingEndpointId?: string | null
Set up a webhook endpoint for this provider. Some providers (e.g. Stripe) support programmatic creation.
-
type: PaymentProviderType
Provider identifier
-
verifyWebhookSignature(): Promise<WebhookVerifyResult>payload: string,signature: string,webhookUrl: string,payloadBytes: Uint8Array
Verify a webhook request's signature and parse the event payload.
& { date: string | null; items: BookingItem[]; eventAnswerIds?: Record<string, number[]>; }
Processed booking intent extracted from payment session metadata
Compact booking item stored in session metadata (serialized/deserialized as JSON)
| { type: "checkout"; checkoutUrl: string; }
| { type: "sold_out"; }
| { type: "checkout_failed"; error?: string; }
| { type: "creation_failed"; reason: "capacity_exceeded" | "encryption_error"; }
Booking result — callers map this to their response format
& { date: string | null; items: CheckoutItem[]; eventAnswerIds?: Record<string, number[]>; }
Registration intent for checkout (one or more events)
| { error: string; }
| null
Result of creating a checkout session.
Supported payment provider identifiers
Supported payment provider identifiers
Valid payment status values
Metadata attached to a validated payment session.
A validated payment session returned after checkout completion
-
amountTotal: number
Total amount charged in smallest currency unit (cents), from the payment provider
- id: string
- metadata: SessionMetadata
- paymentReference: string
- paymentStatus: PaymentStatus
| { success: false; error: string; }
Result of webhook endpoint setup
| { valid: false; error: string; }
Result of webhook signature verification
Stubbable API for internal calls (testable via spyOn, like stripeApi/squareApi)
Square metadata constraint: each value max 255 characters
Stripe metadata constraint: each value max 500 characters
Usage
import * as mod from "docs/payments.ts";