@dodopayments/convex 0.1.1 → 0.2.0
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 +105 -55
- 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
|
@@ -58,48 +58,67 @@ 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
|
|
|
@@ -107,6 +126,7 @@ For handling Dodo Payments webhooks, create a file `convex/http.ts`:
|
|
|
107
126
|
// convex/http.ts
|
|
108
127
|
import { httpRouter } from "convex/server";
|
|
109
128
|
import { createDodoWebhookHandler } from "@dodopayments/convex";
|
|
129
|
+
import { internal } from "./_generated/api";
|
|
110
130
|
|
|
111
131
|
const http = httpRouter();
|
|
112
132
|
|
|
@@ -114,13 +134,24 @@ http.route({
|
|
|
114
134
|
path: "/dodopayments-webhook",
|
|
115
135
|
method: "POST",
|
|
116
136
|
handler: createDodoWebhookHandler({
|
|
117
|
-
onPaymentSucceeded: async (payload) => {
|
|
118
|
-
console.log("Payment succeeded:", payload.data.payment_id);
|
|
119
|
-
//
|
|
137
|
+
onPaymentSucceeded: async (ctx, payload) => {
|
|
138
|
+
console.log("Payment succeeded:", payload.data.payment_id);
|
|
139
|
+
// Update order status in your database
|
|
140
|
+
await ctx.runMutation(internal.orders.markAsPaid, {
|
|
141
|
+
orderId: payload.data.metadata.orderId,
|
|
142
|
+
paymentId: payload.data.payment_id,
|
|
143
|
+
amount: payload.data.amount,
|
|
144
|
+
});
|
|
120
145
|
},
|
|
121
|
-
|
|
146
|
+
|
|
147
|
+
onSubscriptionActive: async (ctx, payload) => {
|
|
122
148
|
console.log("Subscription activated:", payload.data.subscription_id);
|
|
123
|
-
//
|
|
149
|
+
// Create or update subscription record in your database
|
|
150
|
+
await ctx.runMutation(internal.subscriptions.createOrUpdate, {
|
|
151
|
+
subscriptionId: payload.data.subscription_id,
|
|
152
|
+
customerId: payload.data.customer_id,
|
|
153
|
+
status: "active",
|
|
154
|
+
});
|
|
124
155
|
},
|
|
125
156
|
// Add other event handlers as needed
|
|
126
157
|
}),
|
|
@@ -129,11 +160,13 @@ http.route({
|
|
|
129
160
|
export default http;
|
|
130
161
|
```
|
|
131
162
|
|
|
163
|
+
**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.
|
|
164
|
+
|
|
132
165
|
Add your webhook secret in the Convex dashboard (**Settings** → **Environment Variables**):
|
|
133
166
|
|
|
134
167
|
- `DODO_PAYMENTS_WEBHOOK_SECRET=your-webhook-secret`
|
|
135
168
|
|
|
136
|
-
###
|
|
169
|
+
### 6. Define Payment Actions
|
|
137
170
|
|
|
138
171
|
```typescript
|
|
139
172
|
// convex/payments.ts
|
|
@@ -164,7 +197,7 @@ export const createCheckout = action({
|
|
|
164
197
|
});
|
|
165
198
|
```
|
|
166
199
|
|
|
167
|
-
###
|
|
200
|
+
### 7. Frontend Usage
|
|
168
201
|
|
|
169
202
|
```tsx
|
|
170
203
|
import { useAction } from "convex/react";
|
|
@@ -235,44 +268,51 @@ Then add the required environment variables (e.g., DODO_PAYMENTS_API_KEY, DODO_P
|
|
|
235
268
|
DODO_PAYMENTS_API_KEY=your-api-key
|
|
236
269
|
DODO_PAYMENTS_ENVIRONMENT=test_mode
|
|
237
270
|
|
|
238
|
-
Step 3: Create
|
|
271
|
+
Step 3: Create an internal query to fetch users from your database.
|
|
272
|
+
|
|
273
|
+
// convex/users.ts
|
|
274
|
+
import { internalQuery } from "./_generated/server";
|
|
275
|
+
import { v } from "convex/values";
|
|
276
|
+
|
|
277
|
+
// Internal query to fetch user by auth ID
|
|
278
|
+
export const getByAuthId = internalQuery({
|
|
279
|
+
args: { authId: v.string() },
|
|
280
|
+
handler: async (ctx, { authId }) => {
|
|
281
|
+
return await ctx.db
|
|
282
|
+
.query("users")
|
|
283
|
+
.withIndex("by_auth_id", (q) => q.eq("authId", authId))
|
|
284
|
+
.first();
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
Step 4: Create your payment functions file.
|
|
239
289
|
|
|
240
290
|
// convex/dodo.ts
|
|
241
291
|
import { DodoPayments } from "@dodopayments/convex";
|
|
242
292
|
import { components } from "./_generated/api";
|
|
293
|
+
import { internal } from "./_generated/api";
|
|
243
294
|
|
|
244
295
|
export const dodo = new DodoPayments(components.dodopayments, {
|
|
245
296
|
// This function maps your Convex user to a Dodo Payments customer
|
|
246
|
-
// Customize it based on your authentication provider
|
|
297
|
+
// Customize it based on your authentication provider and user database
|
|
298
|
+
|
|
247
299
|
identify: async (ctx) => {
|
|
248
300
|
const identity = await ctx.auth.getUserIdentity();
|
|
249
301
|
if (!identity) {
|
|
250
302
|
return null; // User is not logged in
|
|
251
303
|
}
|
|
252
304
|
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
name: identity.name,
|
|
258
|
-
email: identity.email,
|
|
259
|
-
},
|
|
260
|
-
};
|
|
305
|
+
// Use ctx.runQuery() to lookup user from your database
|
|
306
|
+
const user = await ctx.runQuery(internal.users.getByAuthId, {
|
|
307
|
+
authId: identity.subject,
|
|
308
|
+
});
|
|
261
309
|
|
|
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
310
|
if (!user) {
|
|
267
311
|
return null; // User not found in database
|
|
268
312
|
}
|
|
269
|
-
|
|
313
|
+
|
|
270
314
|
return {
|
|
271
|
-
dodoCustomerId: user.dodoCustomerId, //
|
|
272
|
-
customerData: {
|
|
273
|
-
name: user.name,
|
|
274
|
-
email: user.email,
|
|
275
|
-
},
|
|
315
|
+
dodoCustomerId: user.dodoCustomerId, // Replace user.dodoCustomerId with your field storing Dodo Payments customer ID
|
|
276
316
|
};
|
|
277
317
|
},
|
|
278
318
|
apiKey: process.env.DODO_PAYMENTS_API_KEY!,
|
|
@@ -282,7 +322,7 @@ export const dodo = new DodoPayments(components.dodopayments, {
|
|
|
282
322
|
// Export the API methods for use in your app
|
|
283
323
|
export const { checkout, customerPortal } = dodo.api();
|
|
284
324
|
|
|
285
|
-
Step
|
|
325
|
+
Step 5: Create actions that use the checkout function.
|
|
286
326
|
|
|
287
327
|
// convex/payments.ts
|
|
288
328
|
import { action } from "./_generated/server";
|
|
@@ -312,7 +352,7 @@ export const createCheckout = action({
|
|
|
312
352
|
},
|
|
313
353
|
});
|
|
314
354
|
|
|
315
|
-
Step
|
|
355
|
+
Step 6: Use in your frontend.
|
|
316
356
|
|
|
317
357
|
// Your frontend component
|
|
318
358
|
import { useAction } from "convex/react";
|
|
@@ -347,9 +387,9 @@ Purpose: This function allows customers to manage their subscriptions and paymen
|
|
|
347
387
|
|
|
348
388
|
Integration Steps:
|
|
349
389
|
|
|
350
|
-
Follow Steps 1-
|
|
390
|
+
Follow Steps 1-4 from the Checkout Function section, then:
|
|
351
391
|
|
|
352
|
-
Step
|
|
392
|
+
Step 5: Create a customer portal action.
|
|
353
393
|
|
|
354
394
|
// convex/payments.ts (add to existing file)
|
|
355
395
|
import { action } from "./_generated/server";
|
|
@@ -365,7 +405,7 @@ export const getCustomerPortal = action({
|
|
|
365
405
|
},
|
|
366
406
|
});
|
|
367
407
|
|
|
368
|
-
Step
|
|
408
|
+
Step 6: Use in your frontend.
|
|
369
409
|
|
|
370
410
|
// Your frontend component
|
|
371
411
|
import { useAction } from "convex/react";
|
|
@@ -409,6 +449,7 @@ Step 2: Create a file `convex/http.ts`:
|
|
|
409
449
|
// convex/http.ts
|
|
410
450
|
import { httpRouter } from "convex/server";
|
|
411
451
|
import { createDodoWebhookHandler } from "@dodopayments/convex";
|
|
452
|
+
import { internal } from "./_generated/api";
|
|
412
453
|
|
|
413
454
|
const http = httpRouter();
|
|
414
455
|
|
|
@@ -416,13 +457,22 @@ http.route({
|
|
|
416
457
|
path: "/dodopayments-webhook",
|
|
417
458
|
method: "POST",
|
|
418
459
|
handler: createDodoWebhookHandler({
|
|
419
|
-
onPaymentSucceeded: async (payload) => {
|
|
460
|
+
onPaymentSucceeded: async (ctx, payload) => {
|
|
420
461
|
console.log("Payment succeeded:", payload.data.payment_id);
|
|
421
|
-
//
|
|
462
|
+
// Update order status in your database
|
|
463
|
+
await ctx.runMutation(internal.orders.markAsPaid, {
|
|
464
|
+
orderId: payload.data.metadata.orderId,
|
|
465
|
+
paymentId: payload.data.payment_id,
|
|
466
|
+
});
|
|
422
467
|
},
|
|
423
|
-
|
|
468
|
+
|
|
469
|
+
onSubscriptionActive: async (ctx, payload) => {
|
|
424
470
|
console.log("Subscription activated:", payload.data.subscription_id);
|
|
425
|
-
//
|
|
471
|
+
// Use ctx to create or update subscription records
|
|
472
|
+
await ctx.runMutation(internal.subscriptions.createOrUpdate, {
|
|
473
|
+
subscriptionId: payload.data.subscription_id,
|
|
474
|
+
customerId: payload.data.customer_id,
|
|
475
|
+
});
|
|
426
476
|
},
|
|
427
477
|
// Add other event handlers as needed
|
|
428
478
|
}),
|
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";
|