@dodopayments/opencode-plugin 0.3.3 → 0.5.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 +1 -1
- package/README.md +152 -42
- package/opencode-plugin/README.md +20 -6
- package/opencode-plugin/index.js +27 -1
- package/package.json +5 -5
- package/skills/better-auth-integration/SKILL.md +214 -0
- package/skills/billing-sdk/SKILL.md +357 -370
- package/skills/checkout-integration/SKILL.md +580 -329
- package/skills/credit-based-billing/SKILL.md +448 -775
- package/skills/customer-management/SKILL.md +281 -0
- package/skills/discounts-and-promotions/SKILL.md +464 -0
- package/skills/dodo-best-practices/SKILL.md +471 -0
- package/skills/framework-adapters/SKILL.md +644 -0
- package/skills/license-keys/SKILL.md +324 -199
- package/skills/localized-pricing/SKILL.md +230 -0
- package/skills/mobile-checkout/SKILL.md +521 -0
- package/skills/product-catalog-management/SKILL.md +311 -0
- package/skills/refunds-and-disputes/SKILL.md +333 -0
- package/skills/subscription-integration/SKILL.md +323 -404
- package/skills/testing-and-go-live/SKILL.md +335 -0
- package/skills/usage-based-billing/SKILL.md +339 -479
- package/skills/webhook-integration/SKILL.md +600 -402
- package/skills/best-practices/SKILL.md +0 -315
package/.mcp.json
CHANGED
package/README.md
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# Dodo Payments Agent Plugin
|
|
2
2
|
|
|
3
3
|
[](./LICENSE)
|
|
4
|
-
[](./CHANGELOG.md)
|
|
5
5
|
[](https://www.npmjs.com/package/@dodopayments/opencode-plugin)
|
|
6
6
|
[](https://discord.gg/bYqAp4ayYh)
|
|
7
7
|
|
|
8
|
-
The official Dodo Payments plugin for AI coding agents. Installs
|
|
8
|
+
The official Dodo Payments plugin for AI coding agents. Installs seventeen integration skills and two MCP servers across **Claude Code**, **Codex CLI**, **Cursor**, **VS Code / GitHub Copilot**, and **OpenCode** from a single source of truth.
|
|
9
|
+
|
|
10
|
+
This plugin conforms to the [Agent Plugins 1.0.0](https://agent-plugins.org/specification) specification: a root [`plugin.json`](./plugin.json), skills as immediate children of [`skills/`](./skills), and MCP servers in [`mcp.json`](./mcp.json). Clients with native Agent Plugins support load it directly; the provider-specific manifests in this repo are generated compatibility shims for clients that do not.
|
|
9
11
|
|
|
10
12
|
## What you get
|
|
11
13
|
|
|
12
14
|
- **Dodo Payments API MCP server** - Live API access (payments, subscriptions, customers, products, refunds, licenses, usage). Authenticates via browser OAuth, no local credentials required.
|
|
13
15
|
- **Dodo Knowledge MCP server** - No credentials. Semantic search over the current Dodo Payments documentation.
|
|
14
|
-
- **
|
|
16
|
+
- **Seventeen agent skills** - Written as `SKILL.md` files with YAML frontmatter. Your agent loads the relevant skill on its own when a task calls for it.
|
|
15
17
|
|
|
16
18
|
## Install
|
|
17
19
|
|
|
@@ -26,30 +28,29 @@ The API MCP server uses browser OAuth by default, so no keys are required at ins
|
|
|
26
28
|
|
|
27
29
|
### Codex CLI
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
1. Register the marketplace:
|
|
31
|
+
Register the marketplace, then install the plugin:
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
```bash
|
|
34
|
+
codex plugin marketplace add dodopayments/dodo-agent-plugin
|
|
35
|
+
codex plugin add dodopayments@dodopayments
|
|
36
|
+
```
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
Verify:
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
```bash
|
|
41
|
+
codex plugin list # dodopayments installed, enabled
|
|
42
|
+
codex mcp list # dodo-knowledge, dodopayments-api
|
|
43
|
+
codex mcp login dodopayments-api # browser OAuth, only needed for the API server
|
|
44
|
+
```
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
You can also install from inside the TUI: run `codex`, type `/plugins`, select the **Dodo Payments** marketplace and the **dodopayments** plugin, then choose **Install plugin**.
|
|
44
47
|
|
|
45
|
-
If you
|
|
48
|
+
If you added the marketplace previously and the plugin doesn't appear, refresh it:
|
|
46
49
|
|
|
47
50
|
```bash
|
|
48
51
|
codex plugin marketplace upgrade dodopayments
|
|
49
52
|
```
|
|
50
53
|
|
|
51
|
-
> Codex CLI does not have a `codex plugin install` subcommand. Plugin installation always happens through the in-TUI `/plugins` flow ([official docs](https://developers.openai.com/codex/plugins)).
|
|
52
|
-
|
|
53
54
|
### Cursor
|
|
54
55
|
|
|
55
56
|
Manual install:
|
|
@@ -58,7 +59,42 @@ Manual install:
|
|
|
58
59
|
git clone https://github.com/dodopayments/dodo-agent-plugin.git ~/.cursor/plugins/local/dodo-agent-plugin
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
Restart Cursor. The plugin loads skills from
|
|
62
|
+
Restart Cursor. The plugin loads skills from `skills/` and MCP servers from `.mcp.json`, as declared in `.cursor-plugin/plugin.json`.
|
|
63
|
+
|
|
64
|
+
> Cursor 3.14.27 also recognises Agent Plugins 1.0.0 directly: its agent host carries both spec schema URLs and the spec's own `name` regex, and accepts either `.cursor-plugin/marketplace.json` or `.claude-plugin/marketplace.json` as a marketplace source. The generated `.cursor-plugin/plugin.json` is kept as belt-and-braces for older builds.
|
|
65
|
+
|
|
66
|
+
> Prior to v0.5.0 this clone produced a plugin with **no working skills**: `skills/` contained symlinks into a git submodule that a plain `git clone` does not fetch. Skills are now vendored as real files, so the command above works as documented. If you installed an earlier version, re-clone.
|
|
67
|
+
|
|
68
|
+
### Kiro
|
|
69
|
+
|
|
70
|
+
Kiro reads the Agent Plugins manifest natively and loads this as a Power:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/dodopayments/dodo-agent-plugin.git
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Point Kiro at the cloned folder. Skills load from `skills/`, MCP servers from `mcp.json`, and Kiro-specific presentation comes from the `dev.kiro` extension namespace in `plugin.json`.
|
|
77
|
+
|
|
78
|
+
### Gemini CLI (MCP only)
|
|
79
|
+
|
|
80
|
+
Gemini CLI has no agent-skill primitive, so **only the two MCP servers are available** - the seventeen skills are not. `dodo-knowledge` still covers a good share of what the skills provide, and it stays current automatically.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
git clone https://github.com/dodopayments/dodo-agent-plugin.git \
|
|
84
|
+
~/.gemini/extensions/dodopayments
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Restart Gemini CLI. `gemini-extension.json` at the repo root is the manifest.
|
|
88
|
+
|
|
89
|
+
### VS Code / GitHub Copilot
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git clone https://github.com/dodopayments/dodo-agent-plugin.git
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Then open the Chat view, go to **Plugins**, and add the cloned folder. Skills load from `skills/`, and both MCP servers load from `.mcp.json`.
|
|
96
|
+
|
|
97
|
+
> VS Code 1.125.1 does not key off the Agent Plugins `$schema` - the string appears nowhere in its bundle. Its loader picks a manifest by probing, in order, `.plugin/plugin.json`, then `.claude-plugin/plugin.json`, then a root `plugin.json`, and defaults MCP to `.mcp.json` rather than `mcp.json`. Because this repo ships a generated `.claude-plugin/plugin.json`, VS Code loads it through that branch. Everything works - seventeen skills and two MCP servers - but via the compatibility manifests rather than the spec ones, so VS Code gets the `mcp-remote` bridge rather than the native transports in `mcp.json`.
|
|
62
98
|
|
|
63
99
|
### OpenCode
|
|
64
100
|
|
|
@@ -71,7 +107,29 @@ OpenCode distributes via npm. Add the plugin to your `opencode.json`:
|
|
|
71
107
|
}
|
|
72
108
|
```
|
|
73
109
|
|
|
74
|
-
Restart OpenCode. Both MCP servers (`dodopayments-api`, `dodo-knowledge`) are registered automatically via the plugin's `config` hook
|
|
110
|
+
Restart OpenCode. Both MCP servers (`dodopayments-api`, `dodo-knowledge`) are registered automatically via the plugin's `config` hook. No manual `mcp` block required.
|
|
111
|
+
|
|
112
|
+
**Skills need the package installed locally plus one extra line.** OpenCode does not scan installed packages for skills, so point it at the package's `skills/` directory yourself. `skills.paths` entries resolve against the project directory, so the package must be present in the project's `node_modules` - OpenCode's own plugin cache is not the same location:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npm install --save-dev @dodopayments/opencode-plugin
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```jsonc
|
|
119
|
+
{
|
|
120
|
+
"$schema": "https://opencode.ai/config.json",
|
|
121
|
+
"plugin": ["@dodopayments/opencode-plugin"],
|
|
122
|
+
"skills": {
|
|
123
|
+
"paths": ["node_modules/@dodopayments/opencode-plugin/skills"]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
An absolute path works too, and avoids the local-install requirement.
|
|
129
|
+
|
|
130
|
+
Verify with `opencode run "List every skill available to you by name."` - you should see all seventeen. A skills path that does not exist is ignored silently, so check rather than assume.
|
|
131
|
+
|
|
132
|
+
> Versions before 0.5.0 documented these skills as auto-discovered. They were not: nothing in OpenCode scans an installed package, so OpenCode users had MCP servers but no skills. Setting `config.skills` from the plugin's `config` hook does not fix this either - the skill index is built before `config` hooks run, so it never registers anything.
|
|
75
133
|
|
|
76
134
|
If you prefer the local stdio API server with your own API key instead of the default remote OAuth server, declare `dodopayments-api` yourself in `opencode.json` - your entry wins over the plugin default:
|
|
77
135
|
|
|
@@ -95,18 +153,54 @@ If you prefer the local stdio API server with your own API key instead of the de
|
|
|
95
153
|
|
|
96
154
|
## Included Skills
|
|
97
155
|
|
|
156
|
+
**Getting started**
|
|
157
|
+
|
|
158
|
+
| Skill | Description |
|
|
159
|
+
|-------|-------------|
|
|
160
|
+
| `dodo-best-practices` | SDK setup, environments, API keys, and the canonical checkout-to-webhook architecture |
|
|
161
|
+
| `framework-adapters` | Official `@dodopayments/*` handlers for Next.js, Express, Hono, Astro, Remix, SvelteKit, Nuxt, Fastify, TanStack, Bun, Convex |
|
|
162
|
+
| `testing-and-go-live` | Test mode, test payment methods, webhook testing, production launch checklist |
|
|
163
|
+
|
|
164
|
+
**Accepting payments**
|
|
165
|
+
|
|
166
|
+
| Skill | Description |
|
|
167
|
+
|-------|-------------|
|
|
168
|
+
| `checkout-integration` | Checkout Sessions, payment links, and overlay checkout |
|
|
169
|
+
| `subscription-integration` | Subscription lifecycle, trials, plan changes, proration, on-demand charges |
|
|
170
|
+
| `mobile-checkout` | In-app checkout for React Native, Flutter, iOS, and Android |
|
|
171
|
+
| `webhook-integration` | Receiving and verifying webhooks via the Standard Webhooks spec |
|
|
172
|
+
|
|
173
|
+
**Billing models**
|
|
174
|
+
|
|
175
|
+
| Skill | Description |
|
|
176
|
+
|-------|-------------|
|
|
177
|
+
| `credit-based-billing` | Credit entitlements, balances, ledger, rollover, overage, meter-based deduction |
|
|
178
|
+
| `usage-based-billing` | Meters, event ingestion, aggregation, and per-unit pricing |
|
|
179
|
+
| `license-keys` | License key activation, validation, and instance management |
|
|
180
|
+
|
|
181
|
+
**Catalog and pricing**
|
|
182
|
+
|
|
98
183
|
| Skill | Description |
|
|
99
184
|
|-------|-------------|
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `webhook-integration` | Setting up and handling webhooks for payment events |
|
|
104
|
-
| `usage-based-billing` | Implementing metered billing with events and meters |
|
|
105
|
-
| `credit-based-billing` | Credit entitlements, balances, and metered credit deduction |
|
|
106
|
-
| `license-keys` | Managing license keys for digital products |
|
|
107
|
-
| `billing-sdk` | Using BillingSDK React components |
|
|
185
|
+
| `product-catalog-management` | Products, pricing, add-ons, collections, images, digital delivery |
|
|
186
|
+
| `discounts-and-promotions` | Discount codes, eligibility, stacking, subscription-cycle limits |
|
|
187
|
+
| `localized-pricing` | Localized pricing, adaptive currency, and purchasing power parity |
|
|
108
188
|
|
|
109
|
-
|
|
189
|
+
**Customers and operations**
|
|
190
|
+
|
|
191
|
+
| Skill | Description |
|
|
192
|
+
|-------|-------------|
|
|
193
|
+
| `customer-management` | Customers, self-service portal, payment methods, wallets |
|
|
194
|
+
| `refunds-and-disputes` | Refunds, disputes and chargebacks, access reconciliation |
|
|
195
|
+
|
|
196
|
+
**UI and integrations**
|
|
197
|
+
|
|
198
|
+
| Skill | Description |
|
|
199
|
+
|-------|-------------|
|
|
200
|
+
| `billing-sdk` | BillingSDK React components for pricing tables and billing UI |
|
|
201
|
+
| `better-auth-integration` | The `@dodopayments/better-auth` plugin for customer sync, checkout, portal |
|
|
202
|
+
|
|
203
|
+
Skills source: [`dodopayments/skills`](https://github.com/dodopayments/skills), vendored into `skills/` as real files. Provenance (upstream commit and applied transforms) is recorded in [`.skills-source.json`](./.skills-source.json).
|
|
110
204
|
|
|
111
205
|
## Included MCP Servers
|
|
112
206
|
|
|
@@ -115,11 +209,11 @@ Skills source: [`dodopayments/skills`](https://github.com/dodopayments/skills) (
|
|
|
115
209
|
| `dodopayments-api` | Live API access (payments, subscriptions, customers, products, refunds, licenses, usage) | OAuth (browser) |
|
|
116
210
|
| `dodo-knowledge` | Semantic search over the Dodo Payments documentation | None |
|
|
117
211
|
|
|
118
|
-
Both servers
|
|
212
|
+
Both servers speak Streamable HTTP. The canonical `mcp.json` declares them natively (`type: "streamable-http"`), which is what spec-native clients such as Codex CLI and Cursor use. The generated compatibility manifests — `.mcp.json`, read by Claude Code, VS Code and Cursor's legacy path — wire the same two endpoints through `mcp-remote` instead, so they run in clients that cannot yet dial Streamable HTTP directly.
|
|
119
213
|
|
|
120
214
|
## Configure (optional, Claude Code)
|
|
121
215
|
|
|
122
|
-
If you prefer to run the API MCP locally with an API key instead of the remote
|
|
216
|
+
If you prefer to run the API MCP locally with an API key instead of the remote server, open `/plugins` in Claude Code, select **Dodo Payments**, and choose **Configure options**. Fill in:
|
|
123
217
|
|
|
124
218
|
- `dodo_api_key` - your `dodo_test_...` or `dodo_live_...` key
|
|
125
219
|
- `dodo_webhook_key` - your webhook signing secret
|
|
@@ -177,7 +271,7 @@ These clients load MCPs from the static `.mcp.json` shipped with the plugin. To
|
|
|
177
271
|
"dodopayments-api": {
|
|
178
272
|
"type": "stdio",
|
|
179
273
|
"command": "npx",
|
|
180
|
-
"args": ["-y", "mcp-remote@latest", "https://mcp.dodopayments.com/
|
|
274
|
+
"args": ["-y", "mcp-remote@latest", "https://mcp.dodopayments.com/mcp"],
|
|
181
275
|
"enabled": false
|
|
182
276
|
}
|
|
183
277
|
}
|
|
@@ -202,13 +296,13 @@ Your agent will load the `webhook-integration` skill, use the `dodo-knowledge` M
|
|
|
202
296
|
|
|
203
297
|
## Local development
|
|
204
298
|
|
|
205
|
-
Clone with the skills submodule:
|
|
206
|
-
|
|
207
299
|
```bash
|
|
208
|
-
git clone
|
|
300
|
+
git clone https://github.com/dodopayments/dodo-agent-plugin.git
|
|
209
301
|
cd dodo-agent-plugin
|
|
210
302
|
```
|
|
211
303
|
|
|
304
|
+
No submodules, no build step - `skills/` is vendored as real files.
|
|
305
|
+
|
|
212
306
|
Validate the Claude Code plugin and marketplace:
|
|
213
307
|
|
|
214
308
|
```bash
|
|
@@ -221,12 +315,27 @@ Load the plugin directly for a dev session:
|
|
|
221
315
|
claude --plugin-dir ./dodo-agent-plugin
|
|
222
316
|
```
|
|
223
317
|
|
|
224
|
-
|
|
318
|
+
Verify everything before pushing:
|
|
225
319
|
|
|
226
320
|
```bash
|
|
227
|
-
|
|
321
|
+
npm run verify # generated artifacts in sync + Agent Plugins conformance
|
|
228
322
|
```
|
|
229
323
|
|
|
324
|
+
### Repository layout
|
|
325
|
+
|
|
326
|
+
| Path | Role |
|
|
327
|
+
|---|---|
|
|
328
|
+
| `plugin.json` | **Canonical.** Agent Plugins v1.0.0 manifest and the version source of truth |
|
|
329
|
+
| `mcp.json` | **Canonical.** Agent Plugins v1.0.0 MCP config |
|
|
330
|
+
| `skills/` | **Canonical.** Seventeen skills, vendored as real files |
|
|
331
|
+
| `overlays/*.json` | Hand-authored provider extras the closed spec schema cannot express |
|
|
332
|
+
| `.claude-plugin/`, `.cursor-plugin/`, `.agents/`, `.mcp.json`, `plugins/dodopayments/` | **Generated.** Do not hand-edit - run `npm run build` |
|
|
333
|
+
| `scripts/build.mjs` | The single generator (`--check` for drift) |
|
|
334
|
+
| `scripts/conformance.mjs` | Agent Plugins conformance validator |
|
|
335
|
+
| `.skills-source.json` | Upstream provenance for the vendored skills |
|
|
336
|
+
|
|
337
|
+
Skills are authored in [`dodopayments/skills`](https://github.com/dodopayments/skills) and vendored here. A weekly workflow re-syncs them and opens a PR; run it on demand with the **Sync skills from upstream** workflow dispatch.
|
|
338
|
+
|
|
230
339
|
## For maintainers
|
|
231
340
|
|
|
232
341
|
The repo is configured to publish the OpenCode npm package on every GitHub Release.
|
|
@@ -238,18 +347,19 @@ The repo is configured to publish the OpenCode npm package on every GitHub Relea
|
|
|
238
347
|
|
|
239
348
|
**Release workflow:**
|
|
240
349
|
|
|
241
|
-
1. Bump
|
|
242
|
-
2. Run `
|
|
243
|
-
3.
|
|
244
|
-
4. Create a GitHub Release - the `Publish @dodopayments/opencode-plugin` workflow
|
|
350
|
+
1. Bump `version` in `plugin.json` (the single source of truth).
|
|
351
|
+
2. Run `npm run build` to propagate it to every generated manifest.
|
|
352
|
+
3. Run `npm run verify`, then commit and tag.
|
|
353
|
+
4. Create a GitHub Release - the `Publish @dodopayments/opencode-plugin` workflow publishes to npm with provenance.
|
|
245
354
|
|
|
246
355
|
**Manual dry-run:**
|
|
247
356
|
|
|
248
357
|
- Workflow dispatch with `dry_run: true` to validate the release pipeline without publishing.
|
|
249
358
|
|
|
250
|
-
**CI
|
|
359
|
+
**CI checks:**
|
|
251
360
|
|
|
252
|
-
- `
|
|
361
|
+
- `Verify` runs on every pull request and push to `main`: artifact drift, Agent Plugins conformance, live JSON Schema validation, a "seventeen skills, zero symlinks" assertion, and an npm payload check.
|
|
362
|
+
- The release workflow re-runs the same gates before publishing.
|
|
253
363
|
|
|
254
364
|
## Resources
|
|
255
365
|
|
|
@@ -1,29 +1,43 @@
|
|
|
1
1
|
# @dodopayments/opencode-plugin
|
|
2
2
|
|
|
3
|
-
Official OpenCode plugin for Dodo Payments. Ships
|
|
3
|
+
Official OpenCode plugin for Dodo Payments. Ships seventeen integration skills and auto-registers two MCP servers.
|
|
4
4
|
|
|
5
5
|
This package is part of [`dodopayments/dodo-agent-plugin`](https://github.com/dodopayments/dodo-agent-plugin) - the universal Dodo Payments plugin that also installs into Claude Code, Codex, and Cursor.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Install the package into your project, then add it to `opencode.json`:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install --save-dev @dodopayments/opencode-plugin
|
|
13
|
+
```
|
|
10
14
|
|
|
11
15
|
```jsonc
|
|
12
16
|
{
|
|
13
17
|
"$schema": "https://opencode.ai/config.json",
|
|
14
|
-
"plugin": ["@dodopayments/opencode-plugin"]
|
|
18
|
+
"plugin": ["@dodopayments/opencode-plugin"],
|
|
19
|
+
"skills": {
|
|
20
|
+
"paths": ["node_modules/@dodopayments/opencode-plugin/skills"]
|
|
21
|
+
}
|
|
15
22
|
}
|
|
16
23
|
```
|
|
17
24
|
|
|
18
|
-
Restart OpenCode.
|
|
25
|
+
Restart OpenCode.
|
|
19
26
|
|
|
20
27
|
- Both MCP servers are registered automatically via the plugin's `config` hook.
|
|
21
|
-
- The
|
|
28
|
+
- The `skills.paths` entry is what makes the seventeen skills visible - OpenCode does not scan installed packages for skills. The path resolves against the **project** directory, not OpenCode's plugin cache, which is why the local install above is required. An absolute path works too and avoids that requirement.
|
|
29
|
+
- The plugin module exports only its default function. OpenCode's loader throws `Plugin export is not a function` on any non-function named export, skips the plugin, and swallows the error - leaving you with no MCP servers. Verified on OpenCode 1.18.15.
|
|
22
30
|
- The first call to `dodopayments-api` opens a browser for OAuth. `dodo-knowledge` needs no auth.
|
|
23
31
|
|
|
32
|
+
Verify the install:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
opencode run "List every skill available to you by name."
|
|
36
|
+
```
|
|
37
|
+
|
|
24
38
|
## What you get
|
|
25
39
|
|
|
26
|
-
|
|
40
|
+
Seventeen agent skills (auto-loaded when relevant): `dodo-best-practices`, `framework-adapters`, `testing-and-go-live`, `checkout-integration`, `subscription-integration`, `mobile-checkout`, `webhook-integration`, `credit-based-billing`, `usage-based-billing`, `license-keys`, `product-catalog-management`, `discounts-and-promotions`, `localized-pricing`, `customer-management`, `refunds-and-disputes`, `billing-sdk`, `better-auth-integration`.
|
|
27
41
|
|
|
28
42
|
Two MCP servers (registered automatically):
|
|
29
43
|
|
package/opencode-plugin/index.js
CHANGED
|
@@ -6,12 +6,38 @@
|
|
|
6
6
|
* @typedef {import("@opencode-ai/plugin").Plugin} Plugin
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
// This module must export NOTHING but the default function. OpenCode's loader
|
|
10
|
+
// falls through to `getLegacyPlugins(mod)`, which iterates `Object.values(mod)`
|
|
11
|
+
// and throws `Plugin export is not a function` on any non-function export. The
|
|
12
|
+
// failure is swallowed: the plugin is skipped entirely and the MCP servers
|
|
13
|
+
// below silently vanish. Verified on 1.18.15 - adding a single named object
|
|
14
|
+
// export drops both servers.
|
|
15
|
+
//
|
|
16
|
+
// To re-verify that claim, overwrite the module inside OpenCode's own package
|
|
17
|
+
// cache (~/.cache/opencode/packages/.../node_modules/@dodopayments/...).
|
|
18
|
+
// Editing this checkout, or the project's node_modules, proves nothing:
|
|
19
|
+
// OpenCode resolves the package from that cache and keeps running whatever the
|
|
20
|
+
// registry last published. It does so silently, so the run still looks valid -
|
|
21
|
+
// this has already invalidated two separate bisections of the bug above.
|
|
22
|
+
//
|
|
23
|
+
// Skills are pointed at via `skills.paths` in the user's own opencode.json -
|
|
24
|
+
// see this package's README. Setting `config.skills` from this hook is not a
|
|
25
|
+
// substitute: it never registered skills on any tested version, because the
|
|
26
|
+
// skill index is built before `config` hooks run.
|
|
27
|
+
//
|
|
9
28
|
// Nullish-assign (`??=`) lets users override any entry by declaring the
|
|
10
29
|
// same MCP key in their own opencode.json.
|
|
30
|
+
//
|
|
31
|
+
// The endpoint URLs below MUST match the canonical mcp.json. This file is
|
|
32
|
+
// hand-written rather than generated - OpenCode's config shape is its own
|
|
33
|
+
// (`type: "local"`, `command: [...]`) - so `build.mjs --check` cannot cover
|
|
34
|
+
// it. `scripts/conformance.mjs` asserts the URL sets are identical instead.
|
|
35
|
+
// The `mcp-remote` bridge is deliberate here, matching the generated
|
|
36
|
+
// `.mcp.json`: only the canonical mcp.json uses native streamable-http.
|
|
11
37
|
const DODO_MCP_SERVERS = {
|
|
12
38
|
"dodopayments-api": {
|
|
13
39
|
type: "local",
|
|
14
|
-
command: ["npx", "-y", "mcp-remote@latest", "https://mcp.dodopayments.com/
|
|
40
|
+
command: ["npx", "-y", "mcp-remote@latest", "https://mcp.dodopayments.com/mcp"],
|
|
15
41
|
enabled: true,
|
|
16
42
|
},
|
|
17
43
|
"dodo-knowledge": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dodopayments/opencode-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Dodo Payments skills and MCP server hints for OpenCode.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "opencode-plugin/index.js",
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"LICENSE"
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
17
|
+
"build": "node scripts/build.mjs",
|
|
18
|
+
"build:check": "node scripts/build.mjs --check",
|
|
19
|
+
"conformance": "node scripts/conformance.mjs",
|
|
20
|
+
"verify": "node scripts/build.mjs --check && node scripts/conformance.mjs"
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
23
|
"opencode",
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: better-auth-integration
|
|
3
|
+
description: Guide only for applications using @dodopayments/better-auth, covering authenticated customer sync, checkout, portal access, usage ingestion, and verified webhook callbacks.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Better Auth Integration
|
|
7
|
+
|
|
8
|
+
Use `@dodopayments/better-auth` to synchronize Better Auth users with Dodo Payments and expose authenticated checkout, customer portal, subscription, payment, usage, and webhook endpoints.
|
|
9
|
+
|
|
10
|
+
## When to use this skill
|
|
11
|
+
|
|
12
|
+
- Create a Dodo customer automatically when a Better Auth user signs up.
|
|
13
|
+
- Start checkout for a signed-in user without exposing a Dodo API key.
|
|
14
|
+
- Let users open their customer portal or list their subscriptions and payments.
|
|
15
|
+
- Submit metered usage for the signed-in customer.
|
|
16
|
+
- Receive signature-verified Dodo webhooks through Better Auth.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @dodopayments/better-auth dodopayments better-auth
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The package exports the lowercase server functions `dodopayments`, `checkout`, `portal`, `usage`, and `webhooks`. Its client entry point exports `dodopaymentsClient`.
|
|
25
|
+
|
|
26
|
+
## Server setup
|
|
27
|
+
|
|
28
|
+
Every endpoint is registered by a feature in `use`. Include every feature that the application calls; omitting one makes its route return 404.
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { betterAuth } from "better-auth";
|
|
32
|
+
import DodoPayments from "dodopayments";
|
|
33
|
+
import { checkout, dodopayments, portal, usage, webhooks } from "@dodopayments/better-auth";
|
|
34
|
+
|
|
35
|
+
const dodoPayments = new DodoPayments({
|
|
36
|
+
bearerToken: process.env.DODO_PAYMENTS_API_KEY,
|
|
37
|
+
environment: "test_mode",
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const auth = betterAuth({
|
|
41
|
+
database: {
|
|
42
|
+
// your database config
|
|
43
|
+
},
|
|
44
|
+
plugins: [
|
|
45
|
+
dodopayments({
|
|
46
|
+
client: dodoPayments,
|
|
47
|
+
createCustomerOnSignUp: true,
|
|
48
|
+
// `user` here is Better Auth's base user: id, name, email, emailVerified,
|
|
49
|
+
// image, createdAt, updatedAt. Anything else (phone number, company, plan)
|
|
50
|
+
// must first be declared via `user.additionalFields` in your Better Auth
|
|
51
|
+
// config, otherwise it does not exist on the type and will be undefined.
|
|
52
|
+
getCustomerParams: (user) => ({
|
|
53
|
+
metadata: { better_auth_user_id: user.id },
|
|
54
|
+
}),
|
|
55
|
+
use: [
|
|
56
|
+
checkout({
|
|
57
|
+
products: [
|
|
58
|
+
{ productId: "pdt_premium", slug: "premium-plan" },
|
|
59
|
+
],
|
|
60
|
+
successUrl: "https://app.example.com/billing/success",
|
|
61
|
+
authenticatedUsersOnly: true,
|
|
62
|
+
}),
|
|
63
|
+
portal(),
|
|
64
|
+
usage(),
|
|
65
|
+
webhooks({
|
|
66
|
+
webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY,
|
|
67
|
+
onPayload: async (payload) => {
|
|
68
|
+
console.log("Verified Dodo webhook:", payload.type);
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
],
|
|
72
|
+
}),
|
|
73
|
+
],
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`products` maps an application slug to a Dodo product ID. `authenticatedUsersOnly: true` requires a Better Auth session for checkout. `getCustomerParams` adds application metadata when customer synchronization runs.
|
|
78
|
+
|
|
79
|
+
## Browser client setup
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { createAuthClient } from "better-auth/react";
|
|
83
|
+
import { dodopaymentsClient } from "@dodopayments/better-auth/client";
|
|
84
|
+
|
|
85
|
+
export const authClient = createAuthClient({
|
|
86
|
+
plugins: [dodopaymentsClient()],
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
These are browser methods. They send the Better Auth session cookie automatically; do not pass `request.headers` to them.
|
|
91
|
+
|
|
92
|
+
## Create a checkout session
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { authClient } from "@/lib/auth-client";
|
|
96
|
+
|
|
97
|
+
async function startCheckout() {
|
|
98
|
+
const { data: session, error } = await authClient.dodopayments.checkoutSession({
|
|
99
|
+
slug: "premium-plan",
|
|
100
|
+
referenceId: "order_123",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (error) {
|
|
104
|
+
console.error("Checkout error:", error);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (session) {
|
|
109
|
+
window.location.href = session.url;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`slug` must match a product configured in `checkout({ products: [...] })`. `referenceId` is optional reconciliation metadata.
|
|
115
|
+
|
|
116
|
+
## Open the customer portal
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const { data: portalSession, error } =
|
|
120
|
+
await authClient.dodopayments.customer.portal();
|
|
121
|
+
|
|
122
|
+
if (error) {
|
|
123
|
+
console.error("Portal error:", error);
|
|
124
|
+
} else if (portalSession?.redirect) {
|
|
125
|
+
window.location.href = portalSession.url;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The portal endpoint requires a signed-in, verified user and resolves that user's synchronized Dodo customer.
|
|
130
|
+
|
|
131
|
+
## List subscriptions and payments
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const { data: subscriptions, error: subscriptionsError } =
|
|
135
|
+
await authClient.dodopayments.customer.subscriptions.list({
|
|
136
|
+
query: { page: 1, limit: 10, status: "active" },
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const { data: payments, error: paymentsError } =
|
|
140
|
+
await authClient.dodopayments.customer.payments.list({
|
|
141
|
+
query: { page: 1, limit: 10, status: "succeeded" },
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
if (subscriptionsError || paymentsError) {
|
|
145
|
+
console.error("Could not load billing history");
|
|
146
|
+
} else {
|
|
147
|
+
console.log("Subscriptions:", subscriptions?.items);
|
|
148
|
+
console.log("Payments:", payments?.items);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Both list responses use an `items` envelope. Subscription filters accept `page`, `limit`, and `status`; payment filters use the same pagination fields and payment statuses.
|
|
153
|
+
|
|
154
|
+
## Ingest metered usage
|
|
155
|
+
|
|
156
|
+
Enable `usage()` on the server, then submit an event for the signed-in customer:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const { data, error } = await authClient.dodopayments.usage.ingest({
|
|
160
|
+
event_id: "evt_usage_123",
|
|
161
|
+
event_name: "api_calls",
|
|
162
|
+
metadata: { requests: 100 },
|
|
163
|
+
timestamp: new Date(),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (error) {
|
|
167
|
+
console.error("Usage ingestion failed:", error);
|
|
168
|
+
} else {
|
|
169
|
+
console.log("Ingested events:", data?.ingested_count);
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The plugin derives `customer_id` from the authenticated session. `event_id` is the event's idempotency key; reuse it when retrying the same event.
|
|
174
|
+
|
|
175
|
+
## Webhook endpoint
|
|
176
|
+
|
|
177
|
+
`webhooks({ webhookKey, onPayload })` verifies and handles the request itself. With Better Auth's default `/api/auth` base path, configure this URL in the Dodo dashboard:
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
https://app.example.com/api/auth/dodopayments/webhooks
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Do not create a second route and do not call `auth.api.dodopayments.verifyWebhook()`; that method does not exist. The plugin reads the raw request, verifies the Standard Webhooks signature with `webhookKey`, and invokes `onPayload` plus any configured event-specific callback.
|
|
184
|
+
|
|
185
|
+
## Registered endpoints
|
|
186
|
+
|
|
187
|
+
- `POST /dodopayments/checkout`
|
|
188
|
+
- `POST /dodopayments/checkout-session`
|
|
189
|
+
- `GET /dodopayments/customer/portal`
|
|
190
|
+
- `GET /dodopayments/customer/subscriptions/list`
|
|
191
|
+
- `GET /dodopayments/customer/payments/list`
|
|
192
|
+
- `POST /dodopayments/usage/ingest`
|
|
193
|
+
- `GET /dodopayments/usage/meters/list`
|
|
194
|
+
- `POST /dodopayments/webhooks`
|
|
195
|
+
|
|
196
|
+
Better Auth prefixes these plugin paths with its configured API base path.
|
|
197
|
+
|
|
198
|
+
## Common mistakes
|
|
199
|
+
|
|
200
|
+
**Enabling only `portal()`.** Checkout, usage, and webhook routes do not exist unless `checkout()`, `usage()`, and `webhooks()` are also present in `use`.
|
|
201
|
+
|
|
202
|
+
**Mixing browser and server APIs.** Call `authClient.dodopayments...` in browser code without a `headers` option. Use Better Auth's server API separately when handling server requests.
|
|
203
|
+
|
|
204
|
+
**Creating duplicate customers.** When `createCustomerOnSignUp` is enabled, do not also call `client.customers.create()` for the same user.
|
|
205
|
+
|
|
206
|
+
**Granting access from browser state.** Treat verified webhook events or a server-side Dodo lookup as the source of truth for entitlements.
|
|
207
|
+
|
|
208
|
+
**Adding a custom webhook verifier.** The plugin owns `/dodopayments/webhooks`, signature verification, and callback dispatch.
|
|
209
|
+
|
|
210
|
+
## Resources
|
|
211
|
+
|
|
212
|
+
- [Better Auth Adapter](https://docs.dodopayments.com/developer-resources/better-auth-adaptor)
|
|
213
|
+
- [Dodo Payments Better Auth package](https://www.npmjs.com/package/@dodopayments/better-auth)
|
|
214
|
+
- [Dodo Payments SDK](https://github.com/dodopayments/dodopayments-typescript)
|