@dodopayments/opencode-plugin 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/.mcp.json +22 -0
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/opencode-plugin/README.md +42 -0
- package/opencode-plugin/index.js +30 -0
- package/opencode.json +28 -0
- package/package.json +53 -0
- package/skills/best-practices/SKILL.md +315 -0
- package/skills/billing-sdk/SKILL.md +501 -0
- package/skills/checkout-integration/SKILL.md +599 -0
- package/skills/credit-based-billing/SKILL.md +942 -0
- package/skills/license-keys/SKILL.md +591 -0
- package/skills/subscription-integration/SKILL.md +571 -0
- package/skills/usage-based-billing/SKILL.md +680 -0
- package/skills/webhook-integration/SKILL.md +529 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dodo-best-practices
|
|
3
|
+
description: Comprehensive guide for integrating Dodo Payments - the all-in-one payment and billing platform for SaaS and AI products.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Dodo Payments Integration Guide
|
|
7
|
+
|
|
8
|
+
**Always consult [docs.dodopayments.com](https://docs.dodopayments.com) for the latest API reference and code examples.**
|
|
9
|
+
|
|
10
|
+
Dodo Payments is the all-in-one engine to launch, scale, and monetize worldwide. Designed for SaaS and AI products, it handles payments, billing, subscriptions, and distribution without extra engineering.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Quick Reference
|
|
15
|
+
|
|
16
|
+
### Environment Variables
|
|
17
|
+
- `DODO_PAYMENTS_API_KEY` - Your API key from the dashboard
|
|
18
|
+
- `DODO_PAYMENTS_WEBHOOK_SECRET` - Webhook signing secret for verification
|
|
19
|
+
|
|
20
|
+
### API Environments
|
|
21
|
+
- **Live Mode**: `https://api.dodopayments.com` (default)
|
|
22
|
+
- **Test Mode**: `https://api.dodopayments.com` with `environment: 'test_mode'`
|
|
23
|
+
|
|
24
|
+
### Dashboard URLs
|
|
25
|
+
- **Main Dashboard**: [app.dodopayments.com](https://app.dodopayments.com)
|
|
26
|
+
- **API Keys**: Dashboard → Developer → API
|
|
27
|
+
- **Webhooks**: Dashboard → Developer → Webhooks
|
|
28
|
+
- **Products**: Dashboard → Products
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## SDK Installation
|
|
33
|
+
|
|
34
|
+
### TypeScript/JavaScript
|
|
35
|
+
```bash
|
|
36
|
+
npm install dodopayments
|
|
37
|
+
# or
|
|
38
|
+
yarn add dodopayments
|
|
39
|
+
# or
|
|
40
|
+
pnpm add dodopayments
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import DodoPayments from 'dodopayments';
|
|
45
|
+
|
|
46
|
+
const client = new DodoPayments({
|
|
47
|
+
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
|
|
48
|
+
environment: 'live_mode', // or 'test_mode'
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Python
|
|
53
|
+
```bash
|
|
54
|
+
pip install dodopayments
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from dodopayments import DodoPayments
|
|
59
|
+
|
|
60
|
+
client = DodoPayments(bearer_token=os.environ["DODO_PAYMENTS_API_KEY"])
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Go
|
|
64
|
+
```bash
|
|
65
|
+
go get github.com/dodopayments/dodopayments-go
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```go
|
|
69
|
+
import "github.com/dodopayments/dodopayments-go"
|
|
70
|
+
|
|
71
|
+
client := dodopayments.NewClient(
|
|
72
|
+
option.WithBearerToken(os.Getenv("DODO_PAYMENTS_API_KEY")),
|
|
73
|
+
)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### PHP
|
|
77
|
+
```bash
|
|
78
|
+
composer require dodopayments/client
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```php
|
|
82
|
+
use Dodopayments\Client;
|
|
83
|
+
|
|
84
|
+
$client = new Client(bearerToken: getenv('DODO_PAYMENTS_API_KEY'));
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Core Concepts
|
|
90
|
+
|
|
91
|
+
### Products
|
|
92
|
+
Products are the items you sell. Create them in the dashboard or via API:
|
|
93
|
+
- **One-time**: Single purchase products
|
|
94
|
+
- **Subscription**: Recurring billing products
|
|
95
|
+
- **Usage-based**: Metered billing per consumption
|
|
96
|
+
|
|
97
|
+
### Credit Entitlements
|
|
98
|
+
Credits are virtual balances (API calls, tokens, compute hours) attached to products. Create them in Dashboard → Products → Credits:
|
|
99
|
+
- **Custom Unit**: Your own metric with configurable precision
|
|
100
|
+
- **Fiat Credits**: Real currency value (USD, EUR, etc.)
|
|
101
|
+
- Attach up to 3 credits per product
|
|
102
|
+
- Configure rollover, overage, and expiration per entitlement
|
|
103
|
+
### Checkout Sessions
|
|
104
|
+
The primary way to collect payments. Create a checkout session and redirect customers:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
const session = await client.checkoutSessions.create({
|
|
108
|
+
product_cart: [
|
|
109
|
+
{ product_id: 'prod_xxxxx', quantity: 1 }
|
|
110
|
+
],
|
|
111
|
+
customer: {
|
|
112
|
+
email: 'customer@example.com',
|
|
113
|
+
name: 'John Doe',
|
|
114
|
+
},
|
|
115
|
+
return_url: 'https://yoursite.com/success',
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Redirect customer to: session.checkout_url
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Webhooks
|
|
122
|
+
Listen to events for real-time updates:
|
|
123
|
+
- `payment.succeeded` - Payment completed
|
|
124
|
+
- `payment.failed` - Payment failed
|
|
125
|
+
- `subscription.active` - Subscription activated
|
|
126
|
+
- `subscription.cancelled` - Subscription cancelled
|
|
127
|
+
- `refund.succeeded` - Refund processed
|
|
128
|
+
- `dispute.opened` - Dispute received
|
|
129
|
+
- `license_key.created` - License key generated
|
|
130
|
+
- `credit.added` - Credits granted to customer
|
|
131
|
+
- `credit.deducted` - Credits consumed
|
|
132
|
+
- `credit.balance_low` - Credit balance below threshold
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Common Integration Patterns
|
|
136
|
+
|
|
137
|
+
### One-Time Payment Flow
|
|
138
|
+
|
|
139
|
+
1. Create product in dashboard
|
|
140
|
+
2. Create checkout session with product ID
|
|
141
|
+
3. Redirect customer to checkout URL
|
|
142
|
+
4. Handle `payment.succeeded` webhook
|
|
143
|
+
5. Fulfill order / grant access
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// Create checkout for one-time payment
|
|
147
|
+
const session = await client.checkoutSessions.create({
|
|
148
|
+
product_cart: [{ product_id: 'prod_one_time_product', quantity: 1 }],
|
|
149
|
+
customer: { email: 'customer@example.com' },
|
|
150
|
+
return_url: 'https://yoursite.com/success',
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Subscription Flow
|
|
155
|
+
|
|
156
|
+
1. Create subscription product in dashboard
|
|
157
|
+
2. Create checkout session
|
|
158
|
+
3. Handle `subscription.active` webhook to grant access
|
|
159
|
+
4. Handle `subscription.cancelled` to revoke access
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Create checkout for subscription
|
|
163
|
+
const session = await client.checkoutSessions.create({
|
|
164
|
+
product_cart: [{ product_id: 'prod_monthly_subscription', quantity: 1 }],
|
|
165
|
+
subscription_data: { trial_period_days: 14 }, // Optional trial
|
|
166
|
+
customer: { email: 'customer@example.com' },
|
|
167
|
+
return_url: 'https://yoursite.com/success',
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Webhook Verification
|
|
172
|
+
|
|
173
|
+
Always verify webhook signatures:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import crypto from 'crypto';
|
|
177
|
+
|
|
178
|
+
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
|
|
179
|
+
const expectedSignature = crypto
|
|
180
|
+
.createHmac('sha256', secret)
|
|
181
|
+
.update(payload)
|
|
182
|
+
.digest('hex');
|
|
183
|
+
|
|
184
|
+
return crypto.timingSafeEqual(
|
|
185
|
+
Buffer.from(signature),
|
|
186
|
+
Buffer.from(expectedSignature)
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## API Key Management
|
|
194
|
+
|
|
195
|
+
### Generation
|
|
196
|
+
1. Navigate to Dashboard → Developer → API
|
|
197
|
+
2. Click "Create API Key"
|
|
198
|
+
3. Copy and securely store the key
|
|
199
|
+
|
|
200
|
+
### Security Best Practices
|
|
201
|
+
- Never expose API keys in client-side code
|
|
202
|
+
- Use environment variables
|
|
203
|
+
- Rotate keys periodically
|
|
204
|
+
- Use test mode keys for development
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Customer Portal
|
|
209
|
+
|
|
210
|
+
Allow customers to manage their subscriptions:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const portal = await client.customers.createPortalSession({
|
|
214
|
+
customer_id: 'cust_xxxxx',
|
|
215
|
+
return_url: 'https://yoursite.com/account',
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Redirect to: portal.url
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Error Handling
|
|
224
|
+
|
|
225
|
+
Handle API errors gracefully:
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
try {
|
|
229
|
+
const session = await client.checkoutSessions.create({...});
|
|
230
|
+
} catch (error) {
|
|
231
|
+
if (error.status === 400) {
|
|
232
|
+
// Invalid request - check parameters
|
|
233
|
+
} else if (error.status === 401) {
|
|
234
|
+
// Invalid API key
|
|
235
|
+
} else if (error.status === 429) {
|
|
236
|
+
// Rate limited - implement backoff
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Testing
|
|
244
|
+
|
|
245
|
+
### Test Mode
|
|
246
|
+
- Use test API keys (start with `sk_test_`)
|
|
247
|
+
- Test webhooks with dashboard tools
|
|
248
|
+
- Use test card numbers:
|
|
249
|
+
- `4242 4242 4242 4242` - Success
|
|
250
|
+
- `4000 0000 0000 0002` - Decline
|
|
251
|
+
|
|
252
|
+
### Local Development
|
|
253
|
+
Use ngrok or similar for webhook testing:
|
|
254
|
+
```bash
|
|
255
|
+
ngrok http 3000
|
|
256
|
+
```
|
|
257
|
+
Then configure the ngrok URL as your webhook endpoint in the dashboard.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Framework Integration
|
|
262
|
+
|
|
263
|
+
### Next.js
|
|
264
|
+
Use API routes for server-side operations:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
// app/api/checkout/route.ts
|
|
268
|
+
import { NextResponse } from 'next/server';
|
|
269
|
+
import DodoPayments from 'dodopayments';
|
|
270
|
+
|
|
271
|
+
const client = new DodoPayments({
|
|
272
|
+
bearerToken: process.env.DODO_PAYMENTS_API_KEY!,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
export async function POST(req: Request) {
|
|
276
|
+
const { productId, email } = await req.json();
|
|
277
|
+
|
|
278
|
+
const session = await client.checkoutSessions.create({
|
|
279
|
+
product_cart: [{ product_id: productId, quantity: 1 }],
|
|
280
|
+
customer: { email },
|
|
281
|
+
return_url: `${process.env.NEXT_PUBLIC_URL}/success`,
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
return NextResponse.json({ url: session.checkout_url });
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Express.js
|
|
289
|
+
```typescript
|
|
290
|
+
import express from 'express';
|
|
291
|
+
import DodoPayments from 'dodopayments';
|
|
292
|
+
|
|
293
|
+
const app = express();
|
|
294
|
+
const client = new DodoPayments({ bearerToken: process.env.DODO_PAYMENTS_API_KEY! });
|
|
295
|
+
|
|
296
|
+
app.post('/create-checkout', async (req, res) => {
|
|
297
|
+
const session = await client.checkoutSessions.create({
|
|
298
|
+
product_cart: [{ product_id: req.body.productId, quantity: 1 }],
|
|
299
|
+
customer: { email: req.body.email },
|
|
300
|
+
return_url: 'https://yoursite.com/success',
|
|
301
|
+
});
|
|
302
|
+
res.json({ url: session.checkout_url });
|
|
303
|
+
});
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Resources
|
|
309
|
+
|
|
310
|
+
- [Documentation](https://docs.dodopayments.com)
|
|
311
|
+
- [API Reference](https://docs.dodopayments.com/api-reference/introduction)
|
|
312
|
+
- [SDK Repositories](https://github.com/dodopayments)
|
|
313
|
+
- [Discord Community](https://discord.gg/bYqAp4ayYh)
|
|
314
|
+
- [Support](mailto:support@dodopayments.com)
|
|
315
|
+
- [Credit-Based Billing](https://docs.dodopayments.com/features/credit-based-billing)
|