Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## Unreleased

- Upgrade Stripe Node SDK support to v22.2.1 and document Node.js >=18.
- Add optional `apiVersion` configuration for `StripeSubscriptions` and webhook route registration.
- Add a typed Checkout Session `params` passthrough while keeping the top-level `mode` authoritative.
- Improve webhook robustness for customer deletion, subscription update upserts, invoice upserts, v22 invoice parent metadata, metadata mirroring, and out-of-order invoice status handling.
- Preserve current lint/codegen/workflow dependency hygiene and clear reported npm audit vulnerabilities.

## 0.1.4

- Fix subscription quantity updates outside component actions
Expand Down
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ into your Convex application.

[![npm version](https://badge.fury.io/js/@convex-dev%2Fstripe.svg)](https://badge.fury.io/js/@convex-dev%2Fstripe)

Requires Node.js 18 or later, matching the Stripe Node SDK v22 runtime
requirement.

## Features

- 🛒 **Checkout Sessions** - Create one-time payment and subscription checkouts
Expand Down Expand Up @@ -64,11 +67,13 @@ Add these to your [Convex Dashboard](https://dashboard.convex.dev) → Settings
- `checkout.session.completed`
- `customer.created`
- `customer.updated`
- `customer.deleted`
- `customer.subscription.created`
- `customer.subscription.updated`
- `customer.subscription.deleted`
- `invoice.created`
- `invoice.finalized`
- `invoice.updated`
- `invoice.paid`
- `invoice.payment_failed`
- `payment_intent.succeeded`
Expand All @@ -90,6 +95,7 @@ const http = httpRouter();
// Register Stripe webhook handler at /stripe/webhook
registerRoutes(http, components.stripe, {
webhookPath: "/stripe/webhook",
apiVersion: "2026-04-22.dahlia", // Optional
});

export default http;
Expand Down Expand Up @@ -175,6 +181,7 @@ import { StripeSubscriptions } from "@convex-dev/stripe";

const stripeClient = new StripeSubscriptions(components.stripe, {
STRIPE_SECRET_KEY: "sk_...", // Optional, defaults to process.env.STRIPE_SECRET_KEY
apiVersion: "2026-04-22.dahlia", // Optional Stripe API version
});
```

Expand Down Expand Up @@ -203,9 +210,21 @@ await stripeClient.createCheckoutSession(ctx, {
metadata: {}, // Optional, session metadata
subscriptionMetadata: {}, // Optional, attached to subscription
paymentIntentMetadata: {}, // Optional, attached to payment intent
params: {
allow_promotion_codes: true,
ui_mode: "embedded_page",
return_url: "https://...",
}, // Optional Stripe Checkout Session params
});
```

`params` is a typed passthrough for Stripe Checkout Session fields that the
component does not model directly. Fields in `params` override constructed
defaults, except `mode`, which remains controlled by the top-level `mode`
argument. For non-hosted Checkout UI modes, the component omits `successUrl` and
`cancelUrl` from the Stripe request and expects redirect behavior to be supplied
through Stripe-supported params such as `return_url`.

### Component Queries

Access data directly via the component's public queries:
Expand Down Expand Up @@ -267,13 +286,16 @@ The component automatically handles these Stripe webhook events:
| ------------------------------- | ----------------------------------- |
| `customer.created` | Creates customer record |
| `customer.updated` | Updates customer record |
| `customer.deleted` | Scrubs customer PII |
| `customer.subscription.created` | Creates subscription record |
| `customer.subscription.updated` | Updates subscription record |
| `customer.subscription.deleted` | Marks subscription as canceled |
| `payment_intent.succeeded` | Creates payment record |
| `payment_intent.payment_failed` | Updates payment status |
| `invoice.created` | Creates invoice record |
| `invoice.paid` | Updates invoice to paid |
| `invoice.finalized` | Upserts invoice record |
| `invoice.updated` | Mirrors invoice metadata changes |
| `invoice.paid` | Upserts invoice as paid |
| `invoice.payment_failed` | Marks invoice as failed |
| `checkout.session.completed` | Handles completed checkout sessions |

Expand Down Expand Up @@ -371,6 +393,7 @@ The component creates these tables in its namespace:
| `created` | number | Created timestamp |
| `userId` | string? | Linked user ID |
| `orgId` | string? | Linked org ID |
| `metadata` | object? | Invoice metadata |

## Example App

Expand Down
2 changes: 2 additions & 0 deletions example/convex/stripe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ export const getOrgInvoices = query({
amountDue: v.number(),
amountPaid: v.number(),
created: v.number(),
metadata: v.optional(v.any()),
orgId: v.optional(v.string()),
userId: v.optional(v.string()),
}),
Expand Down Expand Up @@ -530,6 +531,7 @@ export const getCustomerData = query({
amountDue: v.number(),
amountPaid: v.number(),
created: v.number(),
metadata: v.optional(v.any()),
}),
),
}),
Expand Down
Loading
Loading