@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 CHANGED
@@ -6,7 +6,7 @@
6
6
  "args": [
7
7
  "-y",
8
8
  "mcp-remote@latest",
9
- "https://mcp.dodopayments.com/sse"
9
+ "https://mcp.dodopayments.com/mcp"
10
10
  ],
11
11
  "enabled": true
12
12
  },
package/README.md CHANGED
@@ -1,17 +1,19 @@
1
1
  # Dodo Payments Agent Plugin
2
2
 
3
3
  [![License](https://img.shields.io/github/license/dodopayments/dodo-agent-plugin.svg?style=flat-square)](./LICENSE)
4
- [![Version](https://img.shields.io/badge/version-0.2.0-blue.svg?style=flat-square)](./CHANGELOG.md)
4
+ [![Version](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdodopayments%2Fdodo-agent-plugin%2Fmain%2Fplugin.json&query=%24.version&label=version&color=blue&style=flat-square)](./CHANGELOG.md)
5
5
  [![npm](https://img.shields.io/npm/v/@dodopayments/opencode-plugin.svg?style=flat-square)](https://www.npmjs.com/package/@dodopayments/opencode-plugin)
6
6
  [![Discord](https://img.shields.io/discord/1305511580854779984?label=discord&style=flat-square)](https://discord.gg/bYqAp4ayYh)
7
7
 
8
- The official Dodo Payments plugin for AI coding agents. Installs eight integration skills and two MCP servers across **Claude Code**, **Codex CLI**, **Cursor**, and **OpenCode** from a single source of truth.
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
- - **Eight 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.
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
- Codex installs plugins in two steps: register the marketplace from your shell, then install the plugin from inside the Codex TUI.
30
-
31
- 1. Register the marketplace:
31
+ Register the marketplace, then install the plugin:
32
32
 
33
- ```bash
34
- codex plugin marketplace add dodopayments/dodo-agent-plugin
35
- ```
33
+ ```bash
34
+ codex plugin marketplace add dodopayments/dodo-agent-plugin
35
+ codex plugin add dodopayments@dodopayments
36
+ ```
36
37
 
37
- 2. Open Codex and run the `/plugins` slash command:
38
+ Verify:
38
39
 
39
- ```bash
40
- codex
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
- Then type `/plugins`, switch to the **Dodo Payments** marketplace, select the **dodopayments** plugin, and choose **Install plugin**.
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 previously added the marketplace before this fix landed and the plugin doesn't appear under `/plugins`, refresh it:
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 `.claude/skills/` (via Cursor's Claude Code compat) and MCP servers from `.mcp.json`.
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, and the eight skills are auto-discovered from the installed package. No manual `mcp` block required.
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
- | `best-practices` | Comprehensive guide to integrating Dodo Payments with best practices |
101
- | `checkout-integration` | Creating checkout sessions and payment flows |
102
- | `subscription-integration` | Implementing subscription billing flows |
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
- Skills source: [`dodopayments/skills`](https://github.com/dodopayments/skills) (bundled as a git submodule in `skills-src/`).
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 are wired through `mcp-remote` so they run in any MCP-compatible client.
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 SSE server, open `/plugins` in Claude Code, select **Dodo Payments**, and choose **Configure options**. Fill in:
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/sse"],
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 --recurse-submodules https://github.com/dodopayments/dodo-agent-plugin.git
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
- Refresh the bundled skills to the latest upstream version:
318
+ Verify everything before pushing:
225
319
 
226
320
  ```bash
227
- git submodule update --remote skills-src
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 the version in `.claude-plugin/plugin.json`.
242
- 2. Run `node scripts/sync-manifests.mjs` to propagate the version to Cursor, Codex, npm, and marketplace manifests.
243
- 3. Commit and tag.
244
- 4. Create a GitHub Release - the `Publish @dodopayments/opencode-plugin` workflow runs automatically and publishes to npm with provenance.
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 check:**
359
+ **CI checks:**
251
360
 
252
- - `node scripts/sync-manifests.mjs --check` is run by the workflow and fails the release if any manifest is out of sync.
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 eight integration skills and auto-registers two MCP servers.
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
- Add to your `opencode.json`:
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. That's it.
25
+ Restart OpenCode.
19
26
 
20
27
  - Both MCP servers are registered automatically via the plugin's `config` hook.
21
- - The eight skills are auto-discovered from this package's `skills/` directory.
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
- Eight agent skills (auto-loaded when relevant): `best-practices`, `checkout-integration`, `subscription-integration`, `webhook-integration`, `usage-based-billing`, `credit-based-billing`, `license-keys`, `billing-sdk`.
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
 
@@ -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/sse"],
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.3",
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
- "sync": "node scripts/sync-manifests.mjs",
18
- "sync:check": "node scripts/sync-manifests.mjs --check",
19
- "prepack": "node scripts/build-skills-for-npm.mjs materialize",
20
- "postpack": "node scripts/build-skills-for-npm.mjs restore && git checkout skills/"
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)