@dodopayments/convex 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -62
- package/dist/client/index.d.ts +0 -1
- package/dist/index.cjs +174 -148
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +18 -3
- package/dist/index.js +174 -148
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -22,7 +22,6 @@ npm install @dodopayments/convex
|
|
|
22
22
|
|
|
23
23
|
## Quick Start
|
|
24
24
|
|
|
25
|
-
|
|
26
25
|
### 1. Add Component to Convex Config
|
|
27
26
|
|
|
28
27
|
```typescript
|
|
@@ -46,6 +45,7 @@ DODO_PAYMENTS_API_KEY=your-dodo-payments-api-key
|
|
|
46
45
|
DODO_PAYMENTS_ENVIRONMENT=test_mode
|
|
47
46
|
DODO_PAYMENTS_WEBHOOK_SECRET=your-webhook-secret (if using webhooks)
|
|
48
47
|
```
|
|
48
|
+
|
|
49
49
|
```sh
|
|
50
50
|
npx convex dashboard
|
|
51
51
|
```
|
|
@@ -58,55 +58,75 @@ Set the following variables:
|
|
|
58
58
|
|
|
59
59
|
> **Note:** Convex backend functions only read environment variables set in the Convex dashboard. `.env` files are ignored. Always set secrets in the Convex dashboard for both production and development.
|
|
60
60
|
|
|
61
|
-
### 3. Create
|
|
61
|
+
### 3. Create Internal Query
|
|
62
|
+
|
|
63
|
+
First, create an internal query to fetch users from your database. This will be used in the payment functions to identify customers.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// convex/users.ts
|
|
67
|
+
import { internalQuery } from "./_generated/server";
|
|
68
|
+
import { v } from "convex/values";
|
|
69
|
+
|
|
70
|
+
// Internal query to fetch user by auth ID
|
|
71
|
+
export const getByAuthId = internalQuery({
|
|
72
|
+
args: { authId: v.string() },
|
|
73
|
+
handler: async (ctx, { authId }) => {
|
|
74
|
+
return await ctx.db
|
|
75
|
+
.query("users")
|
|
76
|
+
.withIndex("by_auth_id", (q) => q.eq("authId", authId))
|
|
77
|
+
.first();
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 4. Create Payment Functions
|
|
62
83
|
|
|
63
84
|
```typescript
|
|
64
85
|
// convex/dodo.ts
|
|
65
86
|
import { DodoPayments } from "@dodopayments/convex";
|
|
66
87
|
import { components } from "./_generated/api";
|
|
88
|
+
import { internal } from "./_generated/api";
|
|
67
89
|
|
|
68
90
|
export const dodo = new DodoPayments(components.dodopayments, {
|
|
69
91
|
// This function maps your Convex user to a Dodo Payments customer
|
|
70
|
-
// Customize it based on your authentication provider and
|
|
92
|
+
// Customize it based on your authentication provider and user database
|
|
93
|
+
|
|
71
94
|
identify: async (ctx) => {
|
|
72
95
|
const identity = await ctx.auth.getUserIdentity();
|
|
73
96
|
if (!identity) {
|
|
74
97
|
return null; // User is not logged in
|
|
75
98
|
}
|
|
76
99
|
|
|
77
|
-
//
|
|
78
|
-
const user = await ctx.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
email: user.email,
|
|
90
|
-
},
|
|
91
|
-
};
|
|
100
|
+
// Use ctx.runQuery() to lookup user from your database
|
|
101
|
+
const user = await ctx.runQuery(internal.users.getByAuthId, {
|
|
102
|
+
authId: identity.subject,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (!user) {
|
|
106
|
+
return null; // User not found in database
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
dodoCustomerId: user.dodoCustomerId, // Replace user.dodoCustomerId with your field storing Dodo Payments customer ID
|
|
111
|
+
};
|
|
92
112
|
},
|
|
93
113
|
apiKey: process.env.DODO_PAYMENTS_API_KEY!,
|
|
94
114
|
environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
|
|
95
115
|
});
|
|
96
116
|
|
|
97
|
-
export const { checkout, customerPortal } = dodo.api();
|
|
98
117
|
// Export the API methods for use in your app
|
|
99
118
|
export const { checkout, customerPortal } = dodo.api();
|
|
100
119
|
```
|
|
101
120
|
|
|
102
|
-
###
|
|
121
|
+
### 5. Set Up Webhooks (Optional)
|
|
103
122
|
|
|
104
123
|
For handling Dodo Payments webhooks, create a file `convex/http.ts`:
|
|
105
124
|
|
|
106
125
|
```typescript
|
|
107
126
|
// convex/http.ts
|
|
108
|
-
import { httpRouter } from "convex/server";
|
|
109
127
|
import { createDodoWebhookHandler } from "@dodopayments/convex";
|
|
128
|
+
import { httpRouter } from "convex/server";
|
|
129
|
+
import { internal } from "./_generated/api";
|
|
110
130
|
|
|
111
131
|
const http = httpRouter();
|
|
112
132
|
|
|
@@ -114,13 +134,32 @@ http.route({
|
|
|
114
134
|
path: "/dodopayments-webhook",
|
|
115
135
|
method: "POST",
|
|
116
136
|
handler: createDodoWebhookHandler({
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
137
|
+
// Handle successful payments
|
|
138
|
+
onPaymentSucceeded: async (ctx, payload) => {
|
|
139
|
+
console.log("🎉 Payment Succeeded!");
|
|
140
|
+
// Use Convex context to persist payment data
|
|
141
|
+
await ctx.runMutation(internal.webhooks.createPayment, {
|
|
142
|
+
paymentId: payload.data.payment_id,
|
|
143
|
+
businessId: payload.business_id,
|
|
144
|
+
customerEmail: payload.data.customer.email,
|
|
145
|
+
amount: payload.data.total_amount,
|
|
146
|
+
currency: payload.data.currency,
|
|
147
|
+
status: payload.data.status,
|
|
148
|
+
webhookPayload: JSON.stringify(payload),
|
|
149
|
+
});
|
|
120
150
|
},
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
151
|
+
|
|
152
|
+
// Handle subscription activation
|
|
153
|
+
onSubscriptionActive: async (ctx, payload) => {
|
|
154
|
+
console.log("🎉 Subscription Activated!");
|
|
155
|
+
// Use Convex context to persist subscription data
|
|
156
|
+
await ctx.runMutation(internal.webhooks.createSubscription, {
|
|
157
|
+
subscriptionId: payload.data.subscription_id,
|
|
158
|
+
businessId: payload.business_id,
|
|
159
|
+
customerEmail: payload.data.customer.email,
|
|
160
|
+
status: payload.data.status,
|
|
161
|
+
webhookPayload: JSON.stringify(payload),
|
|
162
|
+
});
|
|
124
163
|
},
|
|
125
164
|
// Add other event handlers as needed
|
|
126
165
|
}),
|
|
@@ -129,11 +168,15 @@ http.route({
|
|
|
129
168
|
export default http;
|
|
130
169
|
```
|
|
131
170
|
|
|
171
|
+
**Important:** Make sure to define the corresponding database mutations in your Convex backend for each webhook event you want to handle. For example, create a `createPayment` mutation to record successful payments or a `createSubscription` mutation to manage subscription state.
|
|
172
|
+
|
|
173
|
+
**Important:** All webhook handlers receive the Convex `ActionCtx` as the first parameter, allowing you to use `ctx.runQuery()` and `ctx.runMutation()` to interact with your database.
|
|
174
|
+
|
|
132
175
|
Add your webhook secret in the Convex dashboard (**Settings** → **Environment Variables**):
|
|
133
176
|
|
|
134
177
|
- `DODO_PAYMENTS_WEBHOOK_SECRET=your-webhook-secret`
|
|
135
178
|
|
|
136
|
-
###
|
|
179
|
+
### 6. Define Payment Actions
|
|
137
180
|
|
|
138
181
|
```typescript
|
|
139
182
|
// convex/payments.ts
|
|
@@ -164,7 +207,7 @@ export const createCheckout = action({
|
|
|
164
207
|
});
|
|
165
208
|
```
|
|
166
209
|
|
|
167
|
-
###
|
|
210
|
+
### 7. Frontend Usage
|
|
168
211
|
|
|
169
212
|
```tsx
|
|
170
213
|
import { useAction } from "convex/react";
|
|
@@ -235,44 +278,51 @@ Then add the required environment variables (e.g., DODO_PAYMENTS_API_KEY, DODO_P
|
|
|
235
278
|
DODO_PAYMENTS_API_KEY=your-api-key
|
|
236
279
|
DODO_PAYMENTS_ENVIRONMENT=test_mode
|
|
237
280
|
|
|
238
|
-
Step 3: Create
|
|
281
|
+
Step 3: Create an internal query to fetch users from your database.
|
|
282
|
+
|
|
283
|
+
// convex/users.ts
|
|
284
|
+
import { internalQuery } from "./_generated/server";
|
|
285
|
+
import { v } from "convex/values";
|
|
286
|
+
|
|
287
|
+
// Internal query to fetch user by auth ID
|
|
288
|
+
export const getByAuthId = internalQuery({
|
|
289
|
+
args: { authId: v.string() },
|
|
290
|
+
handler: async (ctx, { authId }) => {
|
|
291
|
+
return await ctx.db
|
|
292
|
+
.query("users")
|
|
293
|
+
.withIndex("by_auth_id", (q) => q.eq("authId", authId))
|
|
294
|
+
.first();
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
Step 4: Create your payment functions file.
|
|
239
299
|
|
|
240
300
|
// convex/dodo.ts
|
|
241
301
|
import { DodoPayments } from "@dodopayments/convex";
|
|
242
302
|
import { components } from "./_generated/api";
|
|
303
|
+
import { internal } from "./_generated/api";
|
|
243
304
|
|
|
244
305
|
export const dodo = new DodoPayments(components.dodopayments, {
|
|
245
306
|
// This function maps your Convex user to a Dodo Payments customer
|
|
246
|
-
// Customize it based on your authentication provider
|
|
307
|
+
// Customize it based on your authentication provider and user database
|
|
308
|
+
|
|
247
309
|
identify: async (ctx) => {
|
|
248
310
|
const identity = await ctx.auth.getUserIdentity();
|
|
249
311
|
if (!identity) {
|
|
250
312
|
return null; // User is not logged in
|
|
251
313
|
}
|
|
252
314
|
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
name: identity.name,
|
|
258
|
-
email: identity.email,
|
|
259
|
-
},
|
|
260
|
-
};
|
|
315
|
+
// Use ctx.runQuery() to lookup user from your database
|
|
316
|
+
const user = await ctx.runQuery(internal.users.getByAuthId, {
|
|
317
|
+
authId: identity.subject,
|
|
318
|
+
});
|
|
261
319
|
|
|
262
|
-
// Lookup user from your database
|
|
263
|
-
const user = await ctx.db.query("users")
|
|
264
|
-
.withIndex("by_auth_id", (q) => q.eq("authId", identity.subject))
|
|
265
|
-
.first();
|
|
266
320
|
if (!user) {
|
|
267
321
|
return null; // User not found in database
|
|
268
322
|
}
|
|
269
|
-
|
|
323
|
+
|
|
270
324
|
return {
|
|
271
|
-
dodoCustomerId: user.dodoCustomerId, //
|
|
272
|
-
customerData: {
|
|
273
|
-
name: user.name,
|
|
274
|
-
email: user.email,
|
|
275
|
-
},
|
|
325
|
+
dodoCustomerId: user.dodoCustomerId, // Replace user.dodoCustomerId with your field storing Dodo Payments customer ID
|
|
276
326
|
};
|
|
277
327
|
},
|
|
278
328
|
apiKey: process.env.DODO_PAYMENTS_API_KEY!,
|
|
@@ -282,7 +332,7 @@ export const dodo = new DodoPayments(components.dodopayments, {
|
|
|
282
332
|
// Export the API methods for use in your app
|
|
283
333
|
export const { checkout, customerPortal } = dodo.api();
|
|
284
334
|
|
|
285
|
-
Step
|
|
335
|
+
Step 5: Create actions that use the checkout function.
|
|
286
336
|
|
|
287
337
|
// convex/payments.ts
|
|
288
338
|
import { action } from "./_generated/server";
|
|
@@ -312,7 +362,7 @@ export const createCheckout = action({
|
|
|
312
362
|
},
|
|
313
363
|
});
|
|
314
364
|
|
|
315
|
-
Step
|
|
365
|
+
Step 6: Use in your frontend.
|
|
316
366
|
|
|
317
367
|
// Your frontend component
|
|
318
368
|
import { useAction } from "convex/react";
|
|
@@ -347,9 +397,9 @@ Purpose: This function allows customers to manage their subscriptions and paymen
|
|
|
347
397
|
|
|
348
398
|
Integration Steps:
|
|
349
399
|
|
|
350
|
-
Follow Steps 1-
|
|
400
|
+
Follow Steps 1-4 from the Checkout Function section, then:
|
|
351
401
|
|
|
352
|
-
Step
|
|
402
|
+
Step 5: Create a customer portal action.
|
|
353
403
|
|
|
354
404
|
// convex/payments.ts (add to existing file)
|
|
355
405
|
import { action } from "./_generated/server";
|
|
@@ -365,7 +415,7 @@ export const getCustomerPortal = action({
|
|
|
365
415
|
},
|
|
366
416
|
});
|
|
367
417
|
|
|
368
|
-
Step
|
|
418
|
+
Step 6: Use in your frontend.
|
|
369
419
|
|
|
370
420
|
// Your frontend component
|
|
371
421
|
import { useAction } from "convex/react";
|
|
@@ -407,8 +457,9 @@ Do not use .env files for backend functions; always set secrets in the Convex da
|
|
|
407
457
|
Step 2: Create a file `convex/http.ts`:
|
|
408
458
|
|
|
409
459
|
// convex/http.ts
|
|
410
|
-
import { httpRouter } from "convex/server";
|
|
411
460
|
import { createDodoWebhookHandler } from "@dodopayments/convex";
|
|
461
|
+
import { httpRouter } from "convex/server";
|
|
462
|
+
import { internal } from "./_generated/api";
|
|
412
463
|
|
|
413
464
|
const http = httpRouter();
|
|
414
465
|
|
|
@@ -416,13 +467,32 @@ http.route({
|
|
|
416
467
|
path: "/dodopayments-webhook",
|
|
417
468
|
method: "POST",
|
|
418
469
|
handler: createDodoWebhookHandler({
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
470
|
+
// Handle successful payments
|
|
471
|
+
onPaymentSucceeded: async (ctx, payload) => {
|
|
472
|
+
console.log("🎉 Payment Succeeded!");
|
|
473
|
+
// Use Convex context to persist payment data
|
|
474
|
+
await ctx.runMutation(internal.webhooks.createPayment, {
|
|
475
|
+
paymentId: payload.data.payment_id,
|
|
476
|
+
businessId: payload.business_id,
|
|
477
|
+
customerEmail: payload.data.customer.email,
|
|
478
|
+
amount: payload.data.total_amount,
|
|
479
|
+
currency: payload.data.currency,
|
|
480
|
+
status: payload.data.status,
|
|
481
|
+
webhookPayload: JSON.stringify(payload),
|
|
482
|
+
});
|
|
422
483
|
},
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
484
|
+
|
|
485
|
+
// Handle subscription activation
|
|
486
|
+
onSubscriptionActive: async (ctx, payload) => {
|
|
487
|
+
console.log("🎉 Subscription Activated!");
|
|
488
|
+
// Use Convex context to persist subscription data
|
|
489
|
+
await ctx.runMutation(internal.webhooks.createSubscription, {
|
|
490
|
+
subscriptionId: payload.data.subscription_id,
|
|
491
|
+
businessId: payload.business_id,
|
|
492
|
+
customerEmail: payload.data.customer.email,
|
|
493
|
+
status: payload.data.status,
|
|
494
|
+
webhookPayload: JSON.stringify(payload),
|
|
495
|
+
});
|
|
426
496
|
},
|
|
427
497
|
// Add other event handlers as needed
|
|
428
498
|
}),
|
|
@@ -430,6 +500,8 @@ http.route({
|
|
|
430
500
|
|
|
431
501
|
export default http;
|
|
432
502
|
|
|
503
|
+
Note: Make sure to define the corresponding database mutations in your Convex backend for each webhook event you want to handle. For example, create a `createPayment` mutation to record successful payments or a `createSubscription` mutation to manage subscription state.
|
|
504
|
+
|
|
433
505
|
Now, you can set the webhook endpoint URL in your Dodo Payments dashboard to `https://<your-convex-deployment-url>/dodopayments-webhook`.
|
|
434
506
|
|
|
435
507
|
Environment Variable Setup:
|
|
@@ -455,4 +527,3 @@ If the user needs assistance setting up environment variables or deployment, ask
|
|
|
455
527
|
|
|
456
528
|
Run `npx convex dev` after setting up the component to generate the necessary types.
|
|
457
529
|
```
|
|
458
|
-
|
package/dist/client/index.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ export interface DodoPaymentsComponent {
|
|
|
12
12
|
export type DodoPaymentsClientConfig = {
|
|
13
13
|
identify: (ctx: GenericActionCtx<any>) => Promise<{
|
|
14
14
|
dodoCustomerId: string;
|
|
15
|
-
customerData?: any;
|
|
16
15
|
} | null>;
|
|
17
16
|
apiKey: string;
|
|
18
17
|
environment: "test_mode" | "live_mode";
|