diff --git a/.changeset/lucky-papers-act.md b/.changeset/lucky-papers-act.md new file mode 100644 index 00000000000..f98e5bfa7d4 --- /dev/null +++ b/.changeset/lucky-papers-act.md @@ -0,0 +1,5 @@ +--- +'@clerk/backend': minor +--- + +Add types for Commerce webhooks diff --git a/packages/backend/src/api/resources/JSON.ts b/packages/backend/src/api/resources/JSON.ts index 369a215d0e9..e48b8361fe9 100644 --- a/packages/backend/src/api/resources/JSON.ts +++ b/packages/backend/src/api/resources/JSON.ts @@ -63,6 +63,10 @@ export const ObjectType = { TestingToken: 'testing_token', Role: 'role', Permission: 'permission', + CommercePayer: 'commerce_payer', + CommercePaymentAttempt: 'commerce_payment_attempt', + CommerceSubscription: 'commerce_subscription', + CommerceSubscriptionItem: 'commerce_subscription_item', } as const; export type ObjectType = (typeof ObjectType)[keyof typeof ObjectType]; @@ -757,6 +761,136 @@ export interface IdPOAuthAccessTokenJSON extends ClerkResourceJSON { updated_at: number; } +export interface CommercePayerJSON extends ClerkResourceJSON { + object: typeof ObjectType.CommercePayer; + instance_id: string; + user_id?: string; + first_name?: string; + last_name?: string; + email: string; + organization_id?: string; + organization_name?: string; + image_url: string; + created_at: number; + updated_at: number; +} + +export interface CommercePayeeJSON { + id: string; + gateway_type: string; + gateway_external_id: string; + gateway_status: 'active' | 'pending' | 'restricted' | 'disconnected'; +} + +export interface CommerceAmountJSON { + amount: number; + amount_formatted: string; + currency: string; + currency_symbol: string; +} + +export interface CommerceTotalsJSON { + subtotal: CommerceAmountJSON; + tax_total: CommerceAmountJSON; + grand_total: CommerceAmountJSON; +} + +export interface CommercePaymentSourceJSON { + id: string; + gateway: string; + gateway_external_id: string; + gateway_external_account_id?: string; + payment_method: string; + status: 'active' | 'disconnected'; + card_type?: string; + last4?: string; +} + +export interface CommercePaymentFailedReasonJSON { + code: string; + decline_code: string; +} + +export interface CommerceSubscriptionCreditJSON { + amount: CommerceAmountJSON; + cycle_days_remaining: number; + cycle_days_total: number; + cycle_remaining_percent: number; +} + +export interface CommercePlanJSON { + id: string; + instance_id: string; + product_id: string; + name: string; + slug: string; + description?: string; + is_default: boolean; + is_recurring: boolean; + amount: number; + period: 'month' | 'annual'; + interval: number; + has_base_fee: boolean; + currency: string; + annual_monthly_amount: number; + publicly_visible: boolean; +} + +export interface CommerceSubscriptionItemJSON extends ClerkResourceJSON { + object: typeof ObjectType.CommerceSubscriptionItem; + status: 'abandoned' | 'active' | 'canceled' | 'ended' | 'expired' | 'incomplete' | 'past_due' | 'upcoming'; + credit: CommerceSubscriptionCreditJSON; + proration_date: string; + plan_period: 'month' | 'annual'; + period_start: number; + period_end?: number; + canceled_at?: number; + past_due_at?: number; + lifetime_paid: number; + next_payment_amount: number; + next_payment_date: number; + amount: CommerceAmountJSON; + plan: CommercePlanJSON; + plan_id: string; +} + +export interface CommercePaymentAttemptJSON extends ClerkResourceJSON { + object: typeof ObjectType.CommercePaymentAttempt; + instance_id: string; + payment_id: string; + statement_id: string; + gateway_external_id: string; + status: 'pending' | 'paid' | 'failed'; + created_at: number; + updated_at: number; + paid_at?: number; + failed_at?: number; + failed_reason?: CommercePaymentFailedReasonJSON; + billing_date: number; + charge_type: 'checkout' | 'recurring'; + payee: CommercePayeeJSON; + payer: CommercePayerJSON; + totals: CommerceTotalsJSON; + payment_source: CommercePaymentSourceJSON; + subscription_items: CommerceSubscriptionItemJSON[]; +} + +export interface CommerceSubscriptionJSON extends ClerkResourceJSON { + object: typeof ObjectType.CommerceSubscription; + status: 'abandoned' | 'active' | 'canceled' | 'ended' | 'expired' | 'incomplete' | 'past_due' | 'upcoming'; + active_at?: number; + canceled_at?: number; + created_at: number; + ended_at?: number; + past_due_at?: number; + updated_at: number; + latest_payment_id: string; + payer_id: string; + payer: CommercePayerJSON; + payment_source_id: string; + items: CommerceSubscriptionItemJSON[]; +} + export interface WebhooksSvixJSON { svix_url: string; } diff --git a/packages/backend/src/api/resources/Webhooks.ts b/packages/backend/src/api/resources/Webhooks.ts index aba2cbe33f5..18d7c333c59 100644 --- a/packages/backend/src/api/resources/Webhooks.ts +++ b/packages/backend/src/api/resources/Webhooks.ts @@ -1,4 +1,7 @@ import type { + CommercePaymentAttemptJSON, + CommerceSubscriptionItemJSON, + CommerceSubscriptionJSON, DeletedObjectJSON, EmailJSON, OrganizationDomainJSON, @@ -62,6 +65,29 @@ export type PermissionWebhookEvent = Webhook< export type WaitlistEntryWebhookEvent = Webhook<'waitlistEntry.created' | 'waitlistEntry.updated', WaitlistEntryJSON>; +export type CommercePaymentAttemptWebhookEvent = Webhook< + 'paymentAttempt.created' | 'paymentAttempt.updated', + CommercePaymentAttemptJSON +>; + +export type CommerceSubscriptionWebhookEvent = Webhook< + 'subscription.created' | 'subscription.updated' | 'subscription.active' | 'subscription.past_due', + CommerceSubscriptionJSON +>; + +export type CommerceSubscriptionItemWebhookEvent = Webhook< + | 'subscriptionItem.created' + | 'subscriptionItem.updated' + | 'subscriptionItem.active' + | 'subscriptionItem.canceled' + | 'subscriptionItem.upcoming' + | 'subscriptionItem.ended' + | 'subscriptionItem.abandoned' + | 'subscriptionItem.incomplete' + | 'subscriptionItem.past_due', + CommerceSubscriptionItemJSON +>; + export type WebhookEvent = | UserWebhookEvent | SessionWebhookEvent @@ -73,6 +99,9 @@ export type WebhookEvent = | OrganizationInvitationWebhookEvent | RoleWebhookEvent | PermissionWebhookEvent - | WaitlistEntryWebhookEvent; + | WaitlistEntryWebhookEvent + | CommercePaymentAttemptWebhookEvent + | CommerceSubscriptionWebhookEvent + | CommerceSubscriptionItemWebhookEvent; export type WebhookEventType = WebhookEvent['type']; diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index fe902146b11..1df2f628240 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -100,6 +100,17 @@ export type { PaginatedResponseJSON, TestingTokenJSON, WebhooksSvixJSON, + CommercePayerJSON, + CommercePayeeJSON, + CommerceAmountJSON, + CommerceTotalsJSON, + CommercePaymentSourceJSON, + CommercePaymentFailedReasonJSON, + CommerceSubscriptionCreditJSON, + CommercePlanJSON, + CommerceSubscriptionItemJSON, + CommercePaymentAttemptJSON, + CommerceSubscriptionJSON, } from './api/resources/JSON'; /**