This is page 5 of 10. Use http://codebase.md/dodopayments/dodopayments-node?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .devcontainer
│ └── devcontainer.json
├── .github
│ └── workflows
│ ├── ci.yml
│ ├── docker-mcp.yml
│ ├── publish-npm.yml
│ └── release-doctor.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.json
├── .release-please-manifest.json
├── .stats.yml
├── api.md
├── bin
│ ├── check-release-environment
│ ├── cli
│ ├── docker-tags
│ ├── migration-config.json
│ └── publish-npm
├── Brewfile
├── CHANGELOG.md
├── CONTRIBUTING.md
├── eslint.config.mjs
├── examples
│ └── .keep
├── jest.config.ts
├── LICENSE
├── MIGRATION.md
├── package.json
├── packages
│ └── mcp-server
│ ├── .dockerignore
│ ├── build
│ ├── cloudflare-worker
│ │ ├── .gitignore
│ │ ├── biome.json
│ │ ├── package.json
│ │ ├── README.md
│ │ ├── src
│ │ │ ├── app.ts
│ │ │ ├── index.ts
│ │ │ └── utils.ts
│ │ ├── static
│ │ │ └── home.md
│ │ ├── tsconfig.json
│ │ ├── worker-configuration.d.ts
│ │ └── wrangler.jsonc
│ ├── Dockerfile
│ ├── jest.config.ts
│ ├── manifest.json
│ ├── package.json
│ ├── README.md
│ ├── scripts
│ │ ├── copy-bundle-files.cjs
│ │ └── postprocess-dist-package-json.cjs
│ ├── src
│ │ ├── code-tool-paths.cts
│ │ ├── code-tool-types.ts
│ │ ├── code-tool-worker.ts
│ │ ├── code-tool.ts
│ │ ├── compat.ts
│ │ ├── docs-search-tool.ts
│ │ ├── dynamic-tools.ts
│ │ ├── filtering.ts
│ │ ├── headers.ts
│ │ ├── http.ts
│ │ ├── index.ts
│ │ ├── options.ts
│ │ ├── server.ts
│ │ ├── stdio.ts
│ │ ├── tools
│ │ │ ├── addons
│ │ │ │ ├── create-addons.ts
│ │ │ │ ├── list-addons.ts
│ │ │ │ ├── retrieve-addons.ts
│ │ │ │ ├── update-addons.ts
│ │ │ │ └── update-images-addons.ts
│ │ │ ├── brands
│ │ │ │ ├── create-brands.ts
│ │ │ │ ├── list-brands.ts
│ │ │ │ ├── retrieve-brands.ts
│ │ │ │ ├── update-brands.ts
│ │ │ │ └── update-images-brands.ts
│ │ │ ├── checkout-sessions
│ │ │ │ ├── create-checkout-sessions.ts
│ │ │ │ └── retrieve-checkout-sessions.ts
│ │ │ ├── customers
│ │ │ │ ├── create-customers.ts
│ │ │ │ ├── customer-portal
│ │ │ │ │ └── create-customers-customer-portal.ts
│ │ │ │ ├── list-customers.ts
│ │ │ │ ├── retrieve-customers.ts
│ │ │ │ ├── update-customers.ts
│ │ │ │ └── wallets
│ │ │ │ ├── ledger-entries
│ │ │ │ │ ├── create-wallets-customers-ledger-entries.ts
│ │ │ │ │ └── list-wallets-customers-ledger-entries.ts
│ │ │ │ └── list-customers-wallets.ts
│ │ │ ├── discounts
│ │ │ │ ├── create-discounts.ts
│ │ │ │ ├── delete-discounts.ts
│ │ │ │ ├── list-discounts.ts
│ │ │ │ ├── retrieve-discounts.ts
│ │ │ │ └── update-discounts.ts
│ │ │ ├── disputes
│ │ │ │ ├── list-disputes.ts
│ │ │ │ └── retrieve-disputes.ts
│ │ │ ├── index.ts
│ │ │ ├── invoices
│ │ │ │ └── payments
│ │ │ │ ├── retrieve-invoices-payments.ts
│ │ │ │ └── retrieve-refund-invoices-payments.ts
│ │ │ ├── license-key-instances
│ │ │ │ ├── list-license-key-instances.ts
│ │ │ │ ├── retrieve-license-key-instances.ts
│ │ │ │ └── update-license-key-instances.ts
│ │ │ ├── license-keys
│ │ │ │ ├── list-license-keys.ts
│ │ │ │ ├── retrieve-license-keys.ts
│ │ │ │ └── update-license-keys.ts
│ │ │ ├── licenses
│ │ │ │ ├── activate-licenses.ts
│ │ │ │ ├── deactivate-licenses.ts
│ │ │ │ └── validate-licenses.ts
│ │ │ ├── meters
│ │ │ │ ├── archive-meters.ts
│ │ │ │ ├── create-meters.ts
│ │ │ │ ├── list-meters.ts
│ │ │ │ ├── retrieve-meters.ts
│ │ │ │ └── unarchive-meters.ts
│ │ │ ├── misc
│ │ │ │ └── list-supported-countries-misc.ts
│ │ │ ├── payments
│ │ │ │ ├── create-payments.ts
│ │ │ │ ├── list-payments.ts
│ │ │ │ ├── retrieve-line-items-payments.ts
│ │ │ │ └── retrieve-payments.ts
│ │ │ ├── payouts
│ │ │ │ └── list-payouts.ts
│ │ │ ├── products
│ │ │ │ ├── archive-products.ts
│ │ │ │ ├── create-products.ts
│ │ │ │ ├── images
│ │ │ │ │ └── update-products-images.ts
│ │ │ │ ├── list-products.ts
│ │ │ │ ├── retrieve-products.ts
│ │ │ │ ├── unarchive-products.ts
│ │ │ │ ├── update-files-products.ts
│ │ │ │ └── update-products.ts
│ │ │ ├── refunds
│ │ │ │ ├── create-refunds.ts
│ │ │ │ ├── list-refunds.ts
│ │ │ │ └── retrieve-refunds.ts
│ │ │ ├── subscriptions
│ │ │ │ ├── change-plan-subscriptions.ts
│ │ │ │ ├── charge-subscriptions.ts
│ │ │ │ ├── create-subscriptions.ts
│ │ │ │ ├── list-subscriptions.ts
│ │ │ │ ├── retrieve-subscriptions.ts
│ │ │ │ ├── retrieve-usage-history-subscriptions.ts
│ │ │ │ └── update-subscriptions.ts
│ │ │ ├── types.ts
│ │ │ ├── usage-events
│ │ │ │ ├── ingest-usage-events.ts
│ │ │ │ ├── list-usage-events.ts
│ │ │ │ └── retrieve-usage-events.ts
│ │ │ └── webhooks
│ │ │ ├── create-webhooks.ts
│ │ │ ├── delete-webhooks.ts
│ │ │ ├── headers
│ │ │ │ ├── retrieve-webhooks-headers.ts
│ │ │ │ └── update-webhooks-headers.ts
│ │ │ ├── list-webhooks.ts
│ │ │ ├── retrieve-secret-webhooks.ts
│ │ │ ├── retrieve-webhooks.ts
│ │ │ └── update-webhooks.ts
│ │ └── tools.ts
│ ├── tests
│ │ ├── compat.test.ts
│ │ ├── dynamic-tools.test.ts
│ │ ├── options.test.ts
│ │ └── tools.test.ts
│ ├── tsc-multi.json
│ ├── tsconfig.build.json
│ ├── tsconfig.dist-src.json
│ ├── tsconfig.json
│ └── yarn.lock
├── README.md
├── release-please-config.json
├── scripts
│ ├── bootstrap
│ ├── build
│ ├── build-all
│ ├── fast-format
│ ├── format
│ ├── lint
│ ├── mock
│ ├── publish-packages.ts
│ ├── test
│ └── utils
│ ├── attw-report.cjs
│ ├── check-is-in-git-install.sh
│ ├── check-version.cjs
│ ├── fix-index-exports.cjs
│ ├── git-swap.sh
│ ├── make-dist-package-json.cjs
│ ├── postprocess-files.cjs
│ └── upload-artifact.sh
├── SECURITY.md
├── src
│ ├── api-promise.ts
│ ├── client.ts
│ ├── core
│ │ ├── api-promise.ts
│ │ ├── error.ts
│ │ ├── pagination.ts
│ │ ├── README.md
│ │ ├── resource.ts
│ │ └── uploads.ts
│ ├── error.ts
│ ├── index.ts
│ ├── internal
│ │ ├── builtin-types.ts
│ │ ├── detect-platform.ts
│ │ ├── errors.ts
│ │ ├── headers.ts
│ │ ├── parse.ts
│ │ ├── README.md
│ │ ├── request-options.ts
│ │ ├── shim-types.ts
│ │ ├── shims.ts
│ │ ├── to-file.ts
│ │ ├── types.ts
│ │ ├── uploads.ts
│ │ ├── utils
│ │ │ ├── base64.ts
│ │ │ ├── bytes.ts
│ │ │ ├── env.ts
│ │ │ ├── log.ts
│ │ │ ├── path.ts
│ │ │ ├── sleep.ts
│ │ │ ├── uuid.ts
│ │ │ └── values.ts
│ │ └── utils.ts
│ ├── lib
│ │ └── .keep
│ ├── pagination.ts
│ ├── resource.ts
│ ├── resources
│ │ ├── addons.ts
│ │ ├── brands.ts
│ │ ├── checkout-sessions.ts
│ │ ├── customers
│ │ │ ├── customer-portal.ts
│ │ │ ├── customers.ts
│ │ │ ├── index.ts
│ │ │ ├── wallets
│ │ │ │ ├── index.ts
│ │ │ │ ├── ledger-entries.ts
│ │ │ │ └── wallets.ts
│ │ │ └── wallets.ts
│ │ ├── customers.ts
│ │ ├── discounts.ts
│ │ ├── disputes.ts
│ │ ├── index.ts
│ │ ├── invoices
│ │ │ ├── index.ts
│ │ │ ├── invoices.ts
│ │ │ └── payments.ts
│ │ ├── invoices.ts
│ │ ├── license-key-instances.ts
│ │ ├── license-keys.ts
│ │ ├── licenses.ts
│ │ ├── meters.ts
│ │ ├── misc.ts
│ │ ├── payments.ts
│ │ ├── payouts.ts
│ │ ├── products
│ │ │ ├── images.ts
│ │ │ ├── index.ts
│ │ │ └── products.ts
│ │ ├── products.ts
│ │ ├── refunds.ts
│ │ ├── subscriptions.ts
│ │ ├── usage-events.ts
│ │ ├── webhook-events.ts
│ │ ├── webhooks
│ │ │ ├── headers.ts
│ │ │ ├── index.ts
│ │ │ └── webhooks.ts
│ │ └── webhooks.ts
│ ├── resources.ts
│ ├── uploads.ts
│ └── version.ts
├── tests
│ ├── api-resources
│ │ ├── addons.test.ts
│ │ ├── brands.test.ts
│ │ ├── checkout-sessions.test.ts
│ │ ├── customers
│ │ │ ├── customer-portal.test.ts
│ │ │ ├── customers.test.ts
│ │ │ └── wallets
│ │ │ ├── ledger-entries.test.ts
│ │ │ └── wallets.test.ts
│ │ ├── discounts.test.ts
│ │ ├── disputes.test.ts
│ │ ├── license-key-instances.test.ts
│ │ ├── license-keys.test.ts
│ │ ├── licenses.test.ts
│ │ ├── meters.test.ts
│ │ ├── misc.test.ts
│ │ ├── payments.test.ts
│ │ ├── payouts.test.ts
│ │ ├── products
│ │ │ ├── images.test.ts
│ │ │ └── products.test.ts
│ │ ├── refunds.test.ts
│ │ ├── subscriptions.test.ts
│ │ ├── usage-events.test.ts
│ │ └── webhooks
│ │ ├── headers.test.ts
│ │ └── webhooks.test.ts
│ ├── base64.test.ts
│ ├── buildHeaders.test.ts
│ ├── form.test.ts
│ ├── index.test.ts
│ ├── path.test.ts
│ ├── stringifyQuery.test.ts
│ └── uploads.test.ts
├── tsc-multi.json
├── tsconfig.build.json
├── tsconfig.deno.json
├── tsconfig.dist-src.json
├── tsconfig.json
└── yarn.lock
```
# Files
--------------------------------------------------------------------------------
/src/resources/meters.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { APIResource } from '../core/resource';
4 | import { APIPromise } from '../core/api-promise';
5 | import {
6 | DefaultPageNumberPagination,
7 | type DefaultPageNumberPaginationParams,
8 | PagePromise,
9 | } from '../core/pagination';
10 | import { buildHeaders } from '../internal/headers';
11 | import { RequestOptions } from '../internal/request-options';
12 | import { path } from '../internal/utils/path';
13 |
14 | export class Meters extends APIResource {
15 | create(body: MeterCreateParams, options?: RequestOptions): APIPromise<Meter> {
16 | return this._client.post('/meters', { body, ...options });
17 | }
18 |
19 | retrieve(id: string, options?: RequestOptions): APIPromise<Meter> {
20 | return this._client.get(path`/meters/${id}`, options);
21 | }
22 |
23 | list(
24 | query: MeterListParams | null | undefined = {},
25 | options?: RequestOptions,
26 | ): PagePromise<MetersDefaultPageNumberPagination, Meter> {
27 | return this._client.getAPIList('/meters', DefaultPageNumberPagination<Meter>, { query, ...options });
28 | }
29 |
30 | archive(id: string, options?: RequestOptions): APIPromise<void> {
31 | return this._client.delete(path`/meters/${id}`, {
32 | ...options,
33 | headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
34 | });
35 | }
36 |
37 | unarchive(id: string, options?: RequestOptions): APIPromise<void> {
38 | return this._client.post(path`/meters/${id}/unarchive`, {
39 | ...options,
40 | headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
41 | });
42 | }
43 | }
44 |
45 | export type MetersDefaultPageNumberPagination = DefaultPageNumberPagination<Meter>;
46 |
47 | export interface Meter {
48 | id: string;
49 |
50 | aggregation: MeterAggregation;
51 |
52 | business_id: string;
53 |
54 | created_at: string;
55 |
56 | event_name: string;
57 |
58 | measurement_unit: string;
59 |
60 | name: string;
61 |
62 | updated_at: string;
63 |
64 | description?: string | null;
65 |
66 | /**
67 | * A filter structure that combines multiple conditions with logical conjunctions
68 | * (AND/OR).
69 | *
70 | * Supports up to 3 levels of nesting to create complex filter expressions. Each
71 | * filter has a conjunction (and/or) and clauses that can be either direct
72 | * conditions or nested filters.
73 | */
74 | filter?: MeterFilter | null;
75 | }
76 |
77 | export interface MeterAggregation {
78 | /**
79 | * Aggregation type for the meter
80 | */
81 | type: 'count' | 'sum' | 'max' | 'last';
82 |
83 | /**
84 | * Required when type is not COUNT
85 | */
86 | key?: string | null;
87 | }
88 |
89 | /**
90 | * A filter structure that combines multiple conditions with logical conjunctions
91 | * (AND/OR).
92 | *
93 | * Supports up to 3 levels of nesting to create complex filter expressions. Each
94 | * filter has a conjunction (and/or) and clauses that can be either direct
95 | * conditions or nested filters.
96 | */
97 | export interface MeterFilter {
98 | /**
99 | * Filter clauses - can be direct conditions or nested filters (up to 3 levels
100 | * deep)
101 | */
102 | clauses: Array<MeterFilter.DirectFilterCondition> | Array<MeterFilter.NestedMeterFilter>;
103 |
104 | /**
105 | * Logical conjunction to apply between clauses (and/or)
106 | */
107 | conjunction: 'and' | 'or';
108 | }
109 |
110 | export namespace MeterFilter {
111 | /**
112 | * Filter condition with key, operator, and value
113 | */
114 | export interface DirectFilterCondition {
115 | /**
116 | * Filter key to apply
117 | */
118 | key: string;
119 |
120 | operator:
121 | | 'equals'
122 | | 'not_equals'
123 | | 'greater_than'
124 | | 'greater_than_or_equals'
125 | | 'less_than'
126 | | 'less_than_or_equals'
127 | | 'contains'
128 | | 'does_not_contain';
129 |
130 | /**
131 | * Filter value - can be string, number, or boolean
132 | */
133 | value: string | number | boolean;
134 | }
135 |
136 | /**
137 | * Level 1 nested filter - can contain Level 2 filters
138 | */
139 | export interface NestedMeterFilter {
140 | /**
141 | * Level 1: Can be conditions or nested filters (2 more levels allowed)
142 | */
143 | clauses: Array<NestedMeterFilter.Level1FilterCondition> | Array<NestedMeterFilter.Level1NestedFilter>;
144 |
145 | conjunction: 'and' | 'or';
146 | }
147 |
148 | export namespace NestedMeterFilter {
149 | /**
150 | * Filter condition with key, operator, and value
151 | */
152 | export interface Level1FilterCondition {
153 | /**
154 | * Filter key to apply
155 | */
156 | key: string;
157 |
158 | operator:
159 | | 'equals'
160 | | 'not_equals'
161 | | 'greater_than'
162 | | 'greater_than_or_equals'
163 | | 'less_than'
164 | | 'less_than_or_equals'
165 | | 'contains'
166 | | 'does_not_contain';
167 |
168 | /**
169 | * Filter value - can be string, number, or boolean
170 | */
171 | value: string | number | boolean;
172 | }
173 |
174 | /**
175 | * Level 2 nested filter
176 | */
177 | export interface Level1NestedFilter {
178 | /**
179 | * Level 2: Can be conditions or nested filters (1 more level allowed)
180 | */
181 | clauses: Array<Level1NestedFilter.Level2FilterCondition> | Array<Level1NestedFilter.Level2NestedFilter>;
182 |
183 | conjunction: 'and' | 'or';
184 | }
185 |
186 | export namespace Level1NestedFilter {
187 | /**
188 | * Filter condition with key, operator, and value
189 | */
190 | export interface Level2FilterCondition {
191 | /**
192 | * Filter key to apply
193 | */
194 | key: string;
195 |
196 | operator:
197 | | 'equals'
198 | | 'not_equals'
199 | | 'greater_than'
200 | | 'greater_than_or_equals'
201 | | 'less_than'
202 | | 'less_than_or_equals'
203 | | 'contains'
204 | | 'does_not_contain';
205 |
206 | /**
207 | * Filter value - can be string, number, or boolean
208 | */
209 | value: string | number | boolean;
210 | }
211 |
212 | /**
213 | * Level 3 nested filter (final nesting level)
214 | */
215 | export interface Level2NestedFilter {
216 | /**
217 | * Level 3: Filter conditions only (max depth reached)
218 | */
219 | clauses: Array<Level2NestedFilter.Clause>;
220 |
221 | conjunction: 'and' | 'or';
222 | }
223 |
224 | export namespace Level2NestedFilter {
225 | /**
226 | * Filter condition with key, operator, and value
227 | */
228 | export interface Clause {
229 | /**
230 | * Filter key to apply
231 | */
232 | key: string;
233 |
234 | operator:
235 | | 'equals'
236 | | 'not_equals'
237 | | 'greater_than'
238 | | 'greater_than_or_equals'
239 | | 'less_than'
240 | | 'less_than_or_equals'
241 | | 'contains'
242 | | 'does_not_contain';
243 |
244 | /**
245 | * Filter value - can be string, number, or boolean
246 | */
247 | value: string | number | boolean;
248 | }
249 | }
250 | }
251 | }
252 | }
253 |
254 | export interface MeterCreateParams {
255 | /**
256 | * Aggregation configuration for the meter
257 | */
258 | aggregation: MeterAggregation;
259 |
260 | /**
261 | * Event name to track
262 | */
263 | event_name: string;
264 |
265 | /**
266 | * measurement unit
267 | */
268 | measurement_unit: string;
269 |
270 | /**
271 | * Name of the meter
272 | */
273 | name: string;
274 |
275 | /**
276 | * Optional description of the meter
277 | */
278 | description?: string | null;
279 |
280 | /**
281 | * Optional filter to apply to the meter
282 | */
283 | filter?: MeterFilter | null;
284 | }
285 |
286 | export interface MeterListParams extends DefaultPageNumberPaginationParams {
287 | /**
288 | * List archived meters
289 | */
290 | archived?: boolean;
291 | }
292 |
293 | export declare namespace Meters {
294 | export {
295 | type Meter as Meter,
296 | type MeterAggregation as MeterAggregation,
297 | type MeterFilter as MeterFilter,
298 | type MetersDefaultPageNumberPagination as MetersDefaultPageNumberPagination,
299 | type MeterCreateParams as MeterCreateParams,
300 | type MeterListParams as MeterListParams,
301 | };
302 | }
303 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/payouts/list-payouts.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { maybeFilter } from 'dodopayments-mcp/filtering';
4 | import { Metadata, asTextContentResult } from 'dodopayments-mcp/tools/types';
5 |
6 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
7 | import DodoPayments from 'dodopayments';
8 |
9 | export const metadata: Metadata = {
10 | resource: 'payouts',
11 | operation: 'read',
12 | tags: [],
13 | httpMethod: 'get',
14 | httpPath: '/payouts',
15 | operationId: 'list_payouts',
16 | };
17 |
18 | export const tool: Tool = {
19 | name: 'list_payouts',
20 | description:
21 | "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n $ref: '#/$defs/payout_list_response'\n }\n }\n },\n required: [ 'items'\n ],\n $defs: {\n payout_list_response: {\n type: 'object',\n properties: {\n amount: {\n type: 'integer',\n description: 'The total amount of the payout.'\n },\n business_id: {\n type: 'string',\n description: 'The unique identifier of the business associated with the payout.'\n },\n chargebacks: {\n type: 'integer',\n description: 'The total value of chargebacks associated with the payout.'\n },\n created_at: {\n type: 'string',\n description: 'The timestamp when the payout was created, in UTC.',\n format: 'date-time'\n },\n currency: {\n $ref: '#/$defs/currency'\n },\n fee: {\n type: 'integer',\n description: 'The fee charged for processing the payout.'\n },\n payment_method: {\n type: 'string',\n description: 'The payment method used for the payout (e.g., bank transfer, card, etc.).'\n },\n payout_id: {\n type: 'string',\n description: 'The unique identifier of the payout.'\n },\n refunds: {\n type: 'integer',\n description: 'The total value of refunds associated with the payout.'\n },\n status: {\n type: 'string',\n description: 'The current status of the payout.',\n enum: [ 'not_initiated',\n 'in_progress',\n 'on_hold',\n 'failed',\n 'success'\n ]\n },\n tax: {\n type: 'integer',\n description: 'The tax applied to the payout.'\n },\n updated_at: {\n type: 'string',\n description: 'The timestamp when the payout was last updated, in UTC.',\n format: 'date-time'\n },\n name: {\n type: 'string',\n description: 'The name of the payout recipient or purpose.'\n },\n payout_document_url: {\n type: 'string',\n description: 'The URL of the document associated with the payout.'\n },\n remarks: {\n type: 'string',\n description: 'Any additional remarks or notes associated with the payout.'\n }\n },\n required: [ 'amount',\n 'business_id',\n 'chargebacks',\n 'created_at',\n 'currency',\n 'fee',\n 'payment_method',\n 'payout_id',\n 'refunds',\n 'status',\n 'tax',\n 'updated_at'\n ]\n },\n currency: {\n type: 'string',\n enum: [ 'AED',\n 'ALL',\n 'AMD',\n 'ANG',\n 'AOA',\n 'ARS',\n 'AUD',\n 'AWG',\n 'AZN',\n 'BAM',\n 'BBD',\n 'BDT',\n 'BGN',\n 'BHD',\n 'BIF',\n 'BMD',\n 'BND',\n 'BOB',\n 'BRL',\n 'BSD',\n 'BWP',\n 'BYN',\n 'BZD',\n 'CAD',\n 'CHF',\n 'CLP',\n 'CNY',\n 'COP',\n 'CRC',\n 'CUP',\n 'CVE',\n 'CZK',\n 'DJF',\n 'DKK',\n 'DOP',\n 'DZD',\n 'EGP',\n 'ETB',\n 'EUR',\n 'FJD',\n 'FKP',\n 'GBP',\n 'GEL',\n 'GHS',\n 'GIP',\n 'GMD',\n 'GNF',\n 'GTQ',\n 'GYD',\n 'HKD',\n 'HNL',\n 'HRK',\n 'HTG',\n 'HUF',\n 'IDR',\n 'ILS',\n 'INR',\n 'IQD',\n 'JMD',\n 'JOD',\n 'JPY',\n 'KES',\n 'KGS',\n 'KHR',\n 'KMF',\n 'KRW',\n 'KWD',\n 'KYD',\n 'KZT',\n 'LAK',\n 'LBP',\n 'LKR',\n 'LRD',\n 'LSL',\n 'LYD',\n 'MAD',\n 'MDL',\n 'MGA',\n 'MKD',\n 'MMK',\n 'MNT',\n 'MOP',\n 'MRU',\n 'MUR',\n 'MVR',\n 'MWK',\n 'MXN',\n 'MYR',\n 'MZN',\n 'NAD',\n 'NGN',\n 'NIO',\n 'NOK',\n 'NPR',\n 'NZD',\n 'OMR',\n 'PAB',\n 'PEN',\n 'PGK',\n 'PHP',\n 'PKR',\n 'PLN',\n 'PYG',\n 'QAR',\n 'RON',\n 'RSD',\n 'RUB',\n 'RWF',\n 'SAR',\n 'SBD',\n 'SCR',\n 'SEK',\n 'SGD',\n 'SHP',\n 'SLE',\n 'SLL',\n 'SOS',\n 'SRD',\n 'SSP',\n 'STN',\n 'SVC',\n 'SZL',\n 'THB',\n 'TND',\n 'TOP',\n 'TRY',\n 'TTD',\n 'TWD',\n 'TZS',\n 'UAH',\n 'UGX',\n 'USD',\n 'UYU',\n 'UZS',\n 'VES',\n 'VND',\n 'VUV',\n 'WST',\n 'XAF',\n 'XCD',\n 'XOF',\n 'XPF',\n 'YER',\n 'ZAR',\n 'ZMW'\n ]\n }\n }\n}\n```",
22 | inputSchema: {
23 | type: 'object',
24 | properties: {
25 | created_at_gte: {
26 | type: 'string',
27 | description: 'Get payouts created after this time (inclusive)',
28 | format: 'date-time',
29 | },
30 | created_at_lte: {
31 | type: 'string',
32 | description: 'Get payouts created before this time (inclusive)',
33 | format: 'date-time',
34 | },
35 | page_number: {
36 | type: 'integer',
37 | description: 'Page number default is 0',
38 | },
39 | page_size: {
40 | type: 'integer',
41 | description: 'Page size default is 10 max is 100',
42 | },
43 | jq_filter: {
44 | type: 'string',
45 | title: 'jq Filter',
46 | description:
47 | 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
48 | },
49 | },
50 | required: [],
51 | },
52 | annotations: {
53 | readOnlyHint: true,
54 | },
55 | };
56 |
57 | export const handler = async (client: DodoPayments, args: Record<string, unknown> | undefined) => {
58 | const { jq_filter, ...body } = args as any;
59 | const response = await client.payouts.list(body).asResponse();
60 | return asTextContentResult(await maybeFilter(jq_filter, await response.json()));
61 | };
62 |
63 | export default { metadata, tool, handler };
64 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/refunds/create-refunds.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { maybeFilter } from 'dodopayments-mcp/filtering';
4 | import { Metadata, asTextContentResult } from 'dodopayments-mcp/tools/types';
5 |
6 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
7 | import DodoPayments from 'dodopayments';
8 |
9 | export const metadata: Metadata = {
10 | resource: 'refunds',
11 | operation: 'write',
12 | tags: [],
13 | httpMethod: 'post',
14 | httpPath: '/refunds',
15 | operationId: 'create_refund_handler',
16 | };
17 |
18 | export const tool: Tool = {
19 | name: 'create_refunds',
20 | description:
21 | "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/refund',\n $defs: {\n refund: {\n type: 'object',\n properties: {\n business_id: {\n type: 'string',\n description: 'The unique identifier of the business issuing the refund.'\n },\n created_at: {\n type: 'string',\n description: 'The timestamp of when the refund was created in UTC.',\n format: 'date-time'\n },\n customer: {\n $ref: '#/$defs/customer_limited_details'\n },\n is_partial: {\n type: 'boolean',\n description: 'If true the refund is a partial refund'\n },\n metadata: {\n type: 'object',\n description: 'Additional metadata stored with the refund.',\n additionalProperties: true\n },\n payment_id: {\n type: 'string',\n description: 'The unique identifier of the payment associated with the refund.'\n },\n refund_id: {\n type: 'string',\n description: 'The unique identifier of the refund.'\n },\n status: {\n $ref: '#/$defs/refund_status'\n },\n amount: {\n type: 'integer',\n description: 'The refunded amount.'\n },\n currency: {\n $ref: '#/$defs/currency'\n },\n reason: {\n type: 'string',\n description: 'The reason provided for the refund, if any. Optional.'\n }\n },\n required: [ 'business_id',\n 'created_at',\n 'customer',\n 'is_partial',\n 'metadata',\n 'payment_id',\n 'refund_id',\n 'status'\n ]\n },\n customer_limited_details: {\n type: 'object',\n properties: {\n customer_id: {\n type: 'string',\n description: 'Unique identifier for the customer'\n },\n email: {\n type: 'string',\n description: 'Email address of the customer'\n },\n name: {\n type: 'string',\n description: 'Full name of the customer'\n },\n phone_number: {\n type: 'string',\n description: 'Phone number of the customer'\n }\n },\n required: [ 'customer_id',\n 'email',\n 'name'\n ]\n },\n refund_status: {\n type: 'string',\n enum: [ 'succeeded',\n 'failed',\n 'pending',\n 'review'\n ]\n },\n currency: {\n type: 'string',\n enum: [ 'AED',\n 'ALL',\n 'AMD',\n 'ANG',\n 'AOA',\n 'ARS',\n 'AUD',\n 'AWG',\n 'AZN',\n 'BAM',\n 'BBD',\n 'BDT',\n 'BGN',\n 'BHD',\n 'BIF',\n 'BMD',\n 'BND',\n 'BOB',\n 'BRL',\n 'BSD',\n 'BWP',\n 'BYN',\n 'BZD',\n 'CAD',\n 'CHF',\n 'CLP',\n 'CNY',\n 'COP',\n 'CRC',\n 'CUP',\n 'CVE',\n 'CZK',\n 'DJF',\n 'DKK',\n 'DOP',\n 'DZD',\n 'EGP',\n 'ETB',\n 'EUR',\n 'FJD',\n 'FKP',\n 'GBP',\n 'GEL',\n 'GHS',\n 'GIP',\n 'GMD',\n 'GNF',\n 'GTQ',\n 'GYD',\n 'HKD',\n 'HNL',\n 'HRK',\n 'HTG',\n 'HUF',\n 'IDR',\n 'ILS',\n 'INR',\n 'IQD',\n 'JMD',\n 'JOD',\n 'JPY',\n 'KES',\n 'KGS',\n 'KHR',\n 'KMF',\n 'KRW',\n 'KWD',\n 'KYD',\n 'KZT',\n 'LAK',\n 'LBP',\n 'LKR',\n 'LRD',\n 'LSL',\n 'LYD',\n 'MAD',\n 'MDL',\n 'MGA',\n 'MKD',\n 'MMK',\n 'MNT',\n 'MOP',\n 'MRU',\n 'MUR',\n 'MVR',\n 'MWK',\n 'MXN',\n 'MYR',\n 'MZN',\n 'NAD',\n 'NGN',\n 'NIO',\n 'NOK',\n 'NPR',\n 'NZD',\n 'OMR',\n 'PAB',\n 'PEN',\n 'PGK',\n 'PHP',\n 'PKR',\n 'PLN',\n 'PYG',\n 'QAR',\n 'RON',\n 'RSD',\n 'RUB',\n 'RWF',\n 'SAR',\n 'SBD',\n 'SCR',\n 'SEK',\n 'SGD',\n 'SHP',\n 'SLE',\n 'SLL',\n 'SOS',\n 'SRD',\n 'SSP',\n 'STN',\n 'SVC',\n 'SZL',\n 'THB',\n 'TND',\n 'TOP',\n 'TRY',\n 'TTD',\n 'TWD',\n 'TZS',\n 'UAH',\n 'UGX',\n 'USD',\n 'UYU',\n 'UZS',\n 'VES',\n 'VND',\n 'VUV',\n 'WST',\n 'XAF',\n 'XCD',\n 'XOF',\n 'XPF',\n 'YER',\n 'ZAR',\n 'ZMW'\n ]\n }\n }\n}\n```",
22 | inputSchema: {
23 | type: 'object',
24 | properties: {
25 | payment_id: {
26 | type: 'string',
27 | description: 'The unique identifier of the payment to be refunded.',
28 | },
29 | items: {
30 | type: 'array',
31 | description: 'Partially Refund an Individual Item',
32 | items: {
33 | type: 'object',
34 | properties: {
35 | item_id: {
36 | type: 'string',
37 | description: 'The id of the item (i.e. `product_id` or `addon_id`)',
38 | },
39 | amount: {
40 | type: 'integer',
41 | description: 'The amount to refund. if None the whole item is refunded',
42 | },
43 | tax_inclusive: {
44 | type: 'boolean',
45 | description: 'Specify if tax is inclusive of the refund. Default true.',
46 | },
47 | },
48 | required: ['item_id'],
49 | },
50 | },
51 | metadata: {
52 | type: 'object',
53 | description: 'Additional metadata associated with the refund.',
54 | additionalProperties: true,
55 | },
56 | reason: {
57 | type: 'string',
58 | description: 'The reason for the refund, if any. Maximum length is 3000 characters. Optional.',
59 | },
60 | jq_filter: {
61 | type: 'string',
62 | title: 'jq Filter',
63 | description:
64 | 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
65 | },
66 | },
67 | required: ['payment_id'],
68 | },
69 | annotations: {},
70 | };
71 |
72 | export const handler = async (client: DodoPayments, args: Record<string, unknown> | undefined) => {
73 | const { jq_filter, ...body } = args as any;
74 | return asTextContentResult(await maybeFilter(jq_filter, await client.refunds.create(body)));
75 | };
76 |
77 | export default { metadata, tool, handler };
78 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/payments/list-payments.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { maybeFilter } from 'dodopayments-mcp/filtering';
4 | import { Metadata, asTextContentResult } from 'dodopayments-mcp/tools/types';
5 |
6 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
7 | import DodoPayments from 'dodopayments';
8 |
9 | export const metadata: Metadata = {
10 | resource: 'payments',
11 | operation: 'read',
12 | tags: [],
13 | httpMethod: 'get',
14 | httpPath: '/payments',
15 | operationId: 'list_payments_handler',
16 | };
17 |
18 | export const tool: Tool = {
19 | name: 'list_payments',
20 | description:
21 | "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n $ref: '#/$defs/payment_list_response'\n }\n }\n },\n required: [ 'items'\n ],\n $defs: {\n payment_list_response: {\n type: 'object',\n properties: {\n brand_id: {\n type: 'string'\n },\n created_at: {\n type: 'string',\n format: 'date-time'\n },\n currency: {\n $ref: '#/$defs/currency'\n },\n customer: {\n $ref: '#/$defs/customer_limited_details'\n },\n digital_products_delivered: {\n type: 'boolean'\n },\n metadata: {\n type: 'object',\n additionalProperties: true\n },\n payment_id: {\n type: 'string'\n },\n total_amount: {\n type: 'integer'\n },\n payment_method: {\n type: 'string'\n },\n payment_method_type: {\n type: 'string'\n },\n status: {\n $ref: '#/$defs/intent_status'\n },\n subscription_id: {\n type: 'string'\n }\n },\n required: [ 'brand_id',\n 'created_at',\n 'currency',\n 'customer',\n 'digital_products_delivered',\n 'metadata',\n 'payment_id',\n 'total_amount'\n ]\n },\n currency: {\n type: 'string',\n enum: [ 'AED',\n 'ALL',\n 'AMD',\n 'ANG',\n 'AOA',\n 'ARS',\n 'AUD',\n 'AWG',\n 'AZN',\n 'BAM',\n 'BBD',\n 'BDT',\n 'BGN',\n 'BHD',\n 'BIF',\n 'BMD',\n 'BND',\n 'BOB',\n 'BRL',\n 'BSD',\n 'BWP',\n 'BYN',\n 'BZD',\n 'CAD',\n 'CHF',\n 'CLP',\n 'CNY',\n 'COP',\n 'CRC',\n 'CUP',\n 'CVE',\n 'CZK',\n 'DJF',\n 'DKK',\n 'DOP',\n 'DZD',\n 'EGP',\n 'ETB',\n 'EUR',\n 'FJD',\n 'FKP',\n 'GBP',\n 'GEL',\n 'GHS',\n 'GIP',\n 'GMD',\n 'GNF',\n 'GTQ',\n 'GYD',\n 'HKD',\n 'HNL',\n 'HRK',\n 'HTG',\n 'HUF',\n 'IDR',\n 'ILS',\n 'INR',\n 'IQD',\n 'JMD',\n 'JOD',\n 'JPY',\n 'KES',\n 'KGS',\n 'KHR',\n 'KMF',\n 'KRW',\n 'KWD',\n 'KYD',\n 'KZT',\n 'LAK',\n 'LBP',\n 'LKR',\n 'LRD',\n 'LSL',\n 'LYD',\n 'MAD',\n 'MDL',\n 'MGA',\n 'MKD',\n 'MMK',\n 'MNT',\n 'MOP',\n 'MRU',\n 'MUR',\n 'MVR',\n 'MWK',\n 'MXN',\n 'MYR',\n 'MZN',\n 'NAD',\n 'NGN',\n 'NIO',\n 'NOK',\n 'NPR',\n 'NZD',\n 'OMR',\n 'PAB',\n 'PEN',\n 'PGK',\n 'PHP',\n 'PKR',\n 'PLN',\n 'PYG',\n 'QAR',\n 'RON',\n 'RSD',\n 'RUB',\n 'RWF',\n 'SAR',\n 'SBD',\n 'SCR',\n 'SEK',\n 'SGD',\n 'SHP',\n 'SLE',\n 'SLL',\n 'SOS',\n 'SRD',\n 'SSP',\n 'STN',\n 'SVC',\n 'SZL',\n 'THB',\n 'TND',\n 'TOP',\n 'TRY',\n 'TTD',\n 'TWD',\n 'TZS',\n 'UAH',\n 'UGX',\n 'USD',\n 'UYU',\n 'UZS',\n 'VES',\n 'VND',\n 'VUV',\n 'WST',\n 'XAF',\n 'XCD',\n 'XOF',\n 'XPF',\n 'YER',\n 'ZAR',\n 'ZMW'\n ]\n },\n customer_limited_details: {\n type: 'object',\n properties: {\n customer_id: {\n type: 'string',\n description: 'Unique identifier for the customer'\n },\n email: {\n type: 'string',\n description: 'Email address of the customer'\n },\n name: {\n type: 'string',\n description: 'Full name of the customer'\n },\n phone_number: {\n type: 'string',\n description: 'Phone number of the customer'\n }\n },\n required: [ 'customer_id',\n 'email',\n 'name'\n ]\n },\n intent_status: {\n type: 'string',\n enum: [ 'succeeded',\n 'failed',\n 'cancelled',\n 'processing',\n 'requires_customer_action',\n 'requires_merchant_action',\n 'requires_payment_method',\n 'requires_confirmation',\n 'requires_capture',\n 'partially_captured',\n 'partially_captured_and_capturable'\n ]\n }\n }\n}\n```",
22 | inputSchema: {
23 | type: 'object',
24 | properties: {
25 | brand_id: {
26 | type: 'string',
27 | description: 'filter by Brand id',
28 | },
29 | created_at_gte: {
30 | type: 'string',
31 | description: 'Get events after this created time',
32 | format: 'date-time',
33 | },
34 | created_at_lte: {
35 | type: 'string',
36 | description: 'Get events created before this time',
37 | format: 'date-time',
38 | },
39 | customer_id: {
40 | type: 'string',
41 | description: 'Filter by customer id',
42 | },
43 | page_number: {
44 | type: 'integer',
45 | description: 'Page number default is 0',
46 | },
47 | page_size: {
48 | type: 'integer',
49 | description: 'Page size default is 10 max is 100',
50 | },
51 | status: {
52 | type: 'string',
53 | description: 'Filter by status',
54 | enum: [
55 | 'succeeded',
56 | 'failed',
57 | 'cancelled',
58 | 'processing',
59 | 'requires_customer_action',
60 | 'requires_merchant_action',
61 | 'requires_payment_method',
62 | 'requires_confirmation',
63 | 'requires_capture',
64 | 'partially_captured',
65 | 'partially_captured_and_capturable',
66 | ],
67 | },
68 | subscription_id: {
69 | type: 'string',
70 | description: 'Filter by subscription id',
71 | },
72 | jq_filter: {
73 | type: 'string',
74 | title: 'jq Filter',
75 | description:
76 | 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
77 | },
78 | },
79 | required: [],
80 | },
81 | annotations: {
82 | readOnlyHint: true,
83 | },
84 | };
85 |
86 | export const handler = async (client: DodoPayments, args: Record<string, unknown> | undefined) => {
87 | const { jq_filter, ...body } = args as any;
88 | const response = await client.payments.list(body).asResponse();
89 | return asTextContentResult(await maybeFilter(jq_filter, await response.json()));
90 | };
91 |
92 | export default { metadata, tool, handler };
93 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/customers/wallets/ledger-entries/create-wallets-customers-ledger-entries.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { maybeFilter } from 'dodopayments-mcp/filtering';
4 | import { Metadata, asTextContentResult } from 'dodopayments-mcp/tools/types';
5 |
6 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
7 | import DodoPayments from 'dodopayments';
8 |
9 | export const metadata: Metadata = {
10 | resource: 'customers.wallets.ledger_entries',
11 | operation: 'write',
12 | tags: [],
13 | httpMethod: 'post',
14 | httpPath: '/customers/{customer_id}/wallets/ledger-entries',
15 | operationId: 'create_customer_ledger_entry',
16 | };
17 |
18 | export const tool: Tool = {
19 | name: 'create_wallets_customers_ledger_entries',
20 | description:
21 | "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/customer_wallet',\n $defs: {\n customer_wallet: {\n type: 'object',\n properties: {\n balance: {\n type: 'integer'\n },\n created_at: {\n type: 'string',\n format: 'date-time'\n },\n currency: {\n $ref: '#/$defs/currency'\n },\n customer_id: {\n type: 'string'\n },\n updated_at: {\n type: 'string',\n format: 'date-time'\n }\n },\n required: [ 'balance',\n 'created_at',\n 'currency',\n 'customer_id',\n 'updated_at'\n ]\n },\n currency: {\n type: 'string',\n enum: [ 'AED',\n 'ALL',\n 'AMD',\n 'ANG',\n 'AOA',\n 'ARS',\n 'AUD',\n 'AWG',\n 'AZN',\n 'BAM',\n 'BBD',\n 'BDT',\n 'BGN',\n 'BHD',\n 'BIF',\n 'BMD',\n 'BND',\n 'BOB',\n 'BRL',\n 'BSD',\n 'BWP',\n 'BYN',\n 'BZD',\n 'CAD',\n 'CHF',\n 'CLP',\n 'CNY',\n 'COP',\n 'CRC',\n 'CUP',\n 'CVE',\n 'CZK',\n 'DJF',\n 'DKK',\n 'DOP',\n 'DZD',\n 'EGP',\n 'ETB',\n 'EUR',\n 'FJD',\n 'FKP',\n 'GBP',\n 'GEL',\n 'GHS',\n 'GIP',\n 'GMD',\n 'GNF',\n 'GTQ',\n 'GYD',\n 'HKD',\n 'HNL',\n 'HRK',\n 'HTG',\n 'HUF',\n 'IDR',\n 'ILS',\n 'INR',\n 'IQD',\n 'JMD',\n 'JOD',\n 'JPY',\n 'KES',\n 'KGS',\n 'KHR',\n 'KMF',\n 'KRW',\n 'KWD',\n 'KYD',\n 'KZT',\n 'LAK',\n 'LBP',\n 'LKR',\n 'LRD',\n 'LSL',\n 'LYD',\n 'MAD',\n 'MDL',\n 'MGA',\n 'MKD',\n 'MMK',\n 'MNT',\n 'MOP',\n 'MRU',\n 'MUR',\n 'MVR',\n 'MWK',\n 'MXN',\n 'MYR',\n 'MZN',\n 'NAD',\n 'NGN',\n 'NIO',\n 'NOK',\n 'NPR',\n 'NZD',\n 'OMR',\n 'PAB',\n 'PEN',\n 'PGK',\n 'PHP',\n 'PKR',\n 'PLN',\n 'PYG',\n 'QAR',\n 'RON',\n 'RSD',\n 'RUB',\n 'RWF',\n 'SAR',\n 'SBD',\n 'SCR',\n 'SEK',\n 'SGD',\n 'SHP',\n 'SLE',\n 'SLL',\n 'SOS',\n 'SRD',\n 'SSP',\n 'STN',\n 'SVC',\n 'SZL',\n 'THB',\n 'TND',\n 'TOP',\n 'TRY',\n 'TTD',\n 'TWD',\n 'TZS',\n 'UAH',\n 'UGX',\n 'USD',\n 'UYU',\n 'UZS',\n 'VES',\n 'VND',\n 'VUV',\n 'WST',\n 'XAF',\n 'XCD',\n 'XOF',\n 'XPF',\n 'YER',\n 'ZAR',\n 'ZMW'\n ]\n }\n }\n}\n```",
22 | inputSchema: {
23 | type: 'object',
24 | properties: {
25 | customer_id: {
26 | type: 'string',
27 | },
28 | amount: {
29 | type: 'integer',
30 | },
31 | currency: {
32 | $ref: '#/$defs/currency',
33 | },
34 | entry_type: {
35 | type: 'string',
36 | description: 'Type of ledger entry - credit or debit',
37 | enum: ['credit', 'debit'],
38 | },
39 | idempotency_key: {
40 | type: 'string',
41 | description: 'Optional idempotency key to prevent duplicate entries',
42 | },
43 | reason: {
44 | type: 'string',
45 | },
46 | jq_filter: {
47 | type: 'string',
48 | title: 'jq Filter',
49 | description:
50 | 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
51 | },
52 | },
53 | required: ['customer_id', 'amount', 'currency', 'entry_type'],
54 | $defs: {
55 | currency: {
56 | type: 'string',
57 | enum: [
58 | 'AED',
59 | 'ALL',
60 | 'AMD',
61 | 'ANG',
62 | 'AOA',
63 | 'ARS',
64 | 'AUD',
65 | 'AWG',
66 | 'AZN',
67 | 'BAM',
68 | 'BBD',
69 | 'BDT',
70 | 'BGN',
71 | 'BHD',
72 | 'BIF',
73 | 'BMD',
74 | 'BND',
75 | 'BOB',
76 | 'BRL',
77 | 'BSD',
78 | 'BWP',
79 | 'BYN',
80 | 'BZD',
81 | 'CAD',
82 | 'CHF',
83 | 'CLP',
84 | 'CNY',
85 | 'COP',
86 | 'CRC',
87 | 'CUP',
88 | 'CVE',
89 | 'CZK',
90 | 'DJF',
91 | 'DKK',
92 | 'DOP',
93 | 'DZD',
94 | 'EGP',
95 | 'ETB',
96 | 'EUR',
97 | 'FJD',
98 | 'FKP',
99 | 'GBP',
100 | 'GEL',
101 | 'GHS',
102 | 'GIP',
103 | 'GMD',
104 | 'GNF',
105 | 'GTQ',
106 | 'GYD',
107 | 'HKD',
108 | 'HNL',
109 | 'HRK',
110 | 'HTG',
111 | 'HUF',
112 | 'IDR',
113 | 'ILS',
114 | 'INR',
115 | 'IQD',
116 | 'JMD',
117 | 'JOD',
118 | 'JPY',
119 | 'KES',
120 | 'KGS',
121 | 'KHR',
122 | 'KMF',
123 | 'KRW',
124 | 'KWD',
125 | 'KYD',
126 | 'KZT',
127 | 'LAK',
128 | 'LBP',
129 | 'LKR',
130 | 'LRD',
131 | 'LSL',
132 | 'LYD',
133 | 'MAD',
134 | 'MDL',
135 | 'MGA',
136 | 'MKD',
137 | 'MMK',
138 | 'MNT',
139 | 'MOP',
140 | 'MRU',
141 | 'MUR',
142 | 'MVR',
143 | 'MWK',
144 | 'MXN',
145 | 'MYR',
146 | 'MZN',
147 | 'NAD',
148 | 'NGN',
149 | 'NIO',
150 | 'NOK',
151 | 'NPR',
152 | 'NZD',
153 | 'OMR',
154 | 'PAB',
155 | 'PEN',
156 | 'PGK',
157 | 'PHP',
158 | 'PKR',
159 | 'PLN',
160 | 'PYG',
161 | 'QAR',
162 | 'RON',
163 | 'RSD',
164 | 'RUB',
165 | 'RWF',
166 | 'SAR',
167 | 'SBD',
168 | 'SCR',
169 | 'SEK',
170 | 'SGD',
171 | 'SHP',
172 | 'SLE',
173 | 'SLL',
174 | 'SOS',
175 | 'SRD',
176 | 'SSP',
177 | 'STN',
178 | 'SVC',
179 | 'SZL',
180 | 'THB',
181 | 'TND',
182 | 'TOP',
183 | 'TRY',
184 | 'TTD',
185 | 'TWD',
186 | 'TZS',
187 | 'UAH',
188 | 'UGX',
189 | 'USD',
190 | 'UYU',
191 | 'UZS',
192 | 'VES',
193 | 'VND',
194 | 'VUV',
195 | 'WST',
196 | 'XAF',
197 | 'XCD',
198 | 'XOF',
199 | 'XPF',
200 | 'YER',
201 | 'ZAR',
202 | 'ZMW',
203 | ],
204 | },
205 | },
206 | },
207 | annotations: {},
208 | };
209 |
210 | export const handler = async (client: DodoPayments, args: Record<string, unknown> | undefined) => {
211 | const { customer_id, jq_filter, ...body } = args as any;
212 | return asTextContentResult(
213 | await maybeFilter(jq_filter, await client.customers.wallets.ledgerEntries.create(customer_id, body)),
214 | );
215 | };
216 |
217 | export default { metadata, tool, handler };
218 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/customers/wallets/ledger-entries/list-wallets-customers-ledger-entries.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { maybeFilter } from 'dodopayments-mcp/filtering';
4 | import { Metadata, asTextContentResult } from 'dodopayments-mcp/tools/types';
5 |
6 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
7 | import DodoPayments from 'dodopayments';
8 |
9 | export const metadata: Metadata = {
10 | resource: 'customers.wallets.ledger_entries',
11 | operation: 'read',
12 | tags: [],
13 | httpMethod: 'get',
14 | httpPath: '/customers/{customer_id}/wallets/ledger-entries',
15 | operationId: 'get_customer_wallet_transactions',
16 | };
17 |
18 | export const tool: Tool = {
19 | name: 'list_wallets_customers_ledger_entries',
20 | description:
21 | "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n items: {\n type: 'array',\n items: {\n $ref: '#/$defs/customer_wallet_transaction'\n }\n }\n },\n required: [ 'items'\n ],\n $defs: {\n customer_wallet_transaction: {\n type: 'object',\n properties: {\n id: {\n type: 'string'\n },\n after_balance: {\n type: 'integer'\n },\n amount: {\n type: 'integer'\n },\n before_balance: {\n type: 'integer'\n },\n business_id: {\n type: 'string'\n },\n created_at: {\n type: 'string',\n format: 'date-time'\n },\n currency: {\n $ref: '#/$defs/currency'\n },\n customer_id: {\n type: 'string'\n },\n event_type: {\n type: 'string',\n enum: [ 'payment',\n 'payment_reversal',\n 'refund',\n 'refund_reversal',\n 'dispute',\n 'dispute_reversal',\n 'merchant_adjustment'\n ]\n },\n is_credit: {\n type: 'boolean'\n },\n reason: {\n type: 'string'\n },\n reference_object_id: {\n type: 'string'\n }\n },\n required: [ 'id',\n 'after_balance',\n 'amount',\n 'before_balance',\n 'business_id',\n 'created_at',\n 'currency',\n 'customer_id',\n 'event_type',\n 'is_credit'\n ]\n },\n currency: {\n type: 'string',\n enum: [ 'AED',\n 'ALL',\n 'AMD',\n 'ANG',\n 'AOA',\n 'ARS',\n 'AUD',\n 'AWG',\n 'AZN',\n 'BAM',\n 'BBD',\n 'BDT',\n 'BGN',\n 'BHD',\n 'BIF',\n 'BMD',\n 'BND',\n 'BOB',\n 'BRL',\n 'BSD',\n 'BWP',\n 'BYN',\n 'BZD',\n 'CAD',\n 'CHF',\n 'CLP',\n 'CNY',\n 'COP',\n 'CRC',\n 'CUP',\n 'CVE',\n 'CZK',\n 'DJF',\n 'DKK',\n 'DOP',\n 'DZD',\n 'EGP',\n 'ETB',\n 'EUR',\n 'FJD',\n 'FKP',\n 'GBP',\n 'GEL',\n 'GHS',\n 'GIP',\n 'GMD',\n 'GNF',\n 'GTQ',\n 'GYD',\n 'HKD',\n 'HNL',\n 'HRK',\n 'HTG',\n 'HUF',\n 'IDR',\n 'ILS',\n 'INR',\n 'IQD',\n 'JMD',\n 'JOD',\n 'JPY',\n 'KES',\n 'KGS',\n 'KHR',\n 'KMF',\n 'KRW',\n 'KWD',\n 'KYD',\n 'KZT',\n 'LAK',\n 'LBP',\n 'LKR',\n 'LRD',\n 'LSL',\n 'LYD',\n 'MAD',\n 'MDL',\n 'MGA',\n 'MKD',\n 'MMK',\n 'MNT',\n 'MOP',\n 'MRU',\n 'MUR',\n 'MVR',\n 'MWK',\n 'MXN',\n 'MYR',\n 'MZN',\n 'NAD',\n 'NGN',\n 'NIO',\n 'NOK',\n 'NPR',\n 'NZD',\n 'OMR',\n 'PAB',\n 'PEN',\n 'PGK',\n 'PHP',\n 'PKR',\n 'PLN',\n 'PYG',\n 'QAR',\n 'RON',\n 'RSD',\n 'RUB',\n 'RWF',\n 'SAR',\n 'SBD',\n 'SCR',\n 'SEK',\n 'SGD',\n 'SHP',\n 'SLE',\n 'SLL',\n 'SOS',\n 'SRD',\n 'SSP',\n 'STN',\n 'SVC',\n 'SZL',\n 'THB',\n 'TND',\n 'TOP',\n 'TRY',\n 'TTD',\n 'TWD',\n 'TZS',\n 'UAH',\n 'UGX',\n 'USD',\n 'UYU',\n 'UZS',\n 'VES',\n 'VND',\n 'VUV',\n 'WST',\n 'XAF',\n 'XCD',\n 'XOF',\n 'XPF',\n 'YER',\n 'ZAR',\n 'ZMW'\n ]\n }\n }\n}\n```",
22 | inputSchema: {
23 | type: 'object',
24 | properties: {
25 | customer_id: {
26 | type: 'string',
27 | },
28 | currency: {
29 | $ref: '#/$defs/currency',
30 | },
31 | page_number: {
32 | type: 'integer',
33 | },
34 | page_size: {
35 | type: 'integer',
36 | },
37 | jq_filter: {
38 | type: 'string',
39 | title: 'jq Filter',
40 | description:
41 | 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
42 | },
43 | },
44 | required: ['customer_id'],
45 | $defs: {
46 | currency: {
47 | type: 'string',
48 | enum: [
49 | 'AED',
50 | 'ALL',
51 | 'AMD',
52 | 'ANG',
53 | 'AOA',
54 | 'ARS',
55 | 'AUD',
56 | 'AWG',
57 | 'AZN',
58 | 'BAM',
59 | 'BBD',
60 | 'BDT',
61 | 'BGN',
62 | 'BHD',
63 | 'BIF',
64 | 'BMD',
65 | 'BND',
66 | 'BOB',
67 | 'BRL',
68 | 'BSD',
69 | 'BWP',
70 | 'BYN',
71 | 'BZD',
72 | 'CAD',
73 | 'CHF',
74 | 'CLP',
75 | 'CNY',
76 | 'COP',
77 | 'CRC',
78 | 'CUP',
79 | 'CVE',
80 | 'CZK',
81 | 'DJF',
82 | 'DKK',
83 | 'DOP',
84 | 'DZD',
85 | 'EGP',
86 | 'ETB',
87 | 'EUR',
88 | 'FJD',
89 | 'FKP',
90 | 'GBP',
91 | 'GEL',
92 | 'GHS',
93 | 'GIP',
94 | 'GMD',
95 | 'GNF',
96 | 'GTQ',
97 | 'GYD',
98 | 'HKD',
99 | 'HNL',
100 | 'HRK',
101 | 'HTG',
102 | 'HUF',
103 | 'IDR',
104 | 'ILS',
105 | 'INR',
106 | 'IQD',
107 | 'JMD',
108 | 'JOD',
109 | 'JPY',
110 | 'KES',
111 | 'KGS',
112 | 'KHR',
113 | 'KMF',
114 | 'KRW',
115 | 'KWD',
116 | 'KYD',
117 | 'KZT',
118 | 'LAK',
119 | 'LBP',
120 | 'LKR',
121 | 'LRD',
122 | 'LSL',
123 | 'LYD',
124 | 'MAD',
125 | 'MDL',
126 | 'MGA',
127 | 'MKD',
128 | 'MMK',
129 | 'MNT',
130 | 'MOP',
131 | 'MRU',
132 | 'MUR',
133 | 'MVR',
134 | 'MWK',
135 | 'MXN',
136 | 'MYR',
137 | 'MZN',
138 | 'NAD',
139 | 'NGN',
140 | 'NIO',
141 | 'NOK',
142 | 'NPR',
143 | 'NZD',
144 | 'OMR',
145 | 'PAB',
146 | 'PEN',
147 | 'PGK',
148 | 'PHP',
149 | 'PKR',
150 | 'PLN',
151 | 'PYG',
152 | 'QAR',
153 | 'RON',
154 | 'RSD',
155 | 'RUB',
156 | 'RWF',
157 | 'SAR',
158 | 'SBD',
159 | 'SCR',
160 | 'SEK',
161 | 'SGD',
162 | 'SHP',
163 | 'SLE',
164 | 'SLL',
165 | 'SOS',
166 | 'SRD',
167 | 'SSP',
168 | 'STN',
169 | 'SVC',
170 | 'SZL',
171 | 'THB',
172 | 'TND',
173 | 'TOP',
174 | 'TRY',
175 | 'TTD',
176 | 'TWD',
177 | 'TZS',
178 | 'UAH',
179 | 'UGX',
180 | 'USD',
181 | 'UYU',
182 | 'UZS',
183 | 'VES',
184 | 'VND',
185 | 'VUV',
186 | 'WST',
187 | 'XAF',
188 | 'XCD',
189 | 'XOF',
190 | 'XPF',
191 | 'YER',
192 | 'ZAR',
193 | 'ZMW',
194 | ],
195 | },
196 | },
197 | },
198 | annotations: {
199 | readOnlyHint: true,
200 | },
201 | };
202 |
203 | export const handler = async (client: DodoPayments, args: Record<string, unknown> | undefined) => {
204 | const { customer_id, jq_filter, ...body } = args as any;
205 | const response = await client.customers.wallets.ledgerEntries.list(customer_id, body).asResponse();
206 | return asTextContentResult(await maybeFilter(jq_filter, await response.json()));
207 | };
208 |
209 | export default { metadata, tool, handler };
210 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/addons/create-addons.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { maybeFilter } from 'dodopayments-mcp/filtering';
4 | import { Metadata, asTextContentResult } from 'dodopayments-mcp/tools/types';
5 |
6 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
7 | import DodoPayments from 'dodopayments';
8 |
9 | export const metadata: Metadata = {
10 | resource: 'addons',
11 | operation: 'write',
12 | tags: [],
13 | httpMethod: 'post',
14 | httpPath: '/addons',
15 | operationId: 'create_addon',
16 | };
17 |
18 | export const tool: Tool = {
19 | name: 'create_addons',
20 | description:
21 | "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/addon_response',\n $defs: {\n addon_response: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'id of the Addon'\n },\n business_id: {\n type: 'string',\n description: 'Unique identifier for the business to which the addon belongs.'\n },\n created_at: {\n type: 'string',\n description: 'Created time',\n format: 'date-time'\n },\n currency: {\n $ref: '#/$defs/currency'\n },\n name: {\n type: 'string',\n description: 'Name of the Addon'\n },\n price: {\n type: 'integer',\n description: 'Amount of the addon'\n },\n tax_category: {\n $ref: '#/$defs/tax_category'\n },\n updated_at: {\n type: 'string',\n description: 'Updated time',\n format: 'date-time'\n },\n description: {\n type: 'string',\n description: 'Optional description of the Addon'\n },\n image: {\n type: 'string',\n description: 'Image of the Addon'\n }\n },\n required: [ 'id',\n 'business_id',\n 'created_at',\n 'currency',\n 'name',\n 'price',\n 'tax_category',\n 'updated_at'\n ]\n },\n currency: {\n type: 'string',\n enum: [ 'AED',\n 'ALL',\n 'AMD',\n 'ANG',\n 'AOA',\n 'ARS',\n 'AUD',\n 'AWG',\n 'AZN',\n 'BAM',\n 'BBD',\n 'BDT',\n 'BGN',\n 'BHD',\n 'BIF',\n 'BMD',\n 'BND',\n 'BOB',\n 'BRL',\n 'BSD',\n 'BWP',\n 'BYN',\n 'BZD',\n 'CAD',\n 'CHF',\n 'CLP',\n 'CNY',\n 'COP',\n 'CRC',\n 'CUP',\n 'CVE',\n 'CZK',\n 'DJF',\n 'DKK',\n 'DOP',\n 'DZD',\n 'EGP',\n 'ETB',\n 'EUR',\n 'FJD',\n 'FKP',\n 'GBP',\n 'GEL',\n 'GHS',\n 'GIP',\n 'GMD',\n 'GNF',\n 'GTQ',\n 'GYD',\n 'HKD',\n 'HNL',\n 'HRK',\n 'HTG',\n 'HUF',\n 'IDR',\n 'ILS',\n 'INR',\n 'IQD',\n 'JMD',\n 'JOD',\n 'JPY',\n 'KES',\n 'KGS',\n 'KHR',\n 'KMF',\n 'KRW',\n 'KWD',\n 'KYD',\n 'KZT',\n 'LAK',\n 'LBP',\n 'LKR',\n 'LRD',\n 'LSL',\n 'LYD',\n 'MAD',\n 'MDL',\n 'MGA',\n 'MKD',\n 'MMK',\n 'MNT',\n 'MOP',\n 'MRU',\n 'MUR',\n 'MVR',\n 'MWK',\n 'MXN',\n 'MYR',\n 'MZN',\n 'NAD',\n 'NGN',\n 'NIO',\n 'NOK',\n 'NPR',\n 'NZD',\n 'OMR',\n 'PAB',\n 'PEN',\n 'PGK',\n 'PHP',\n 'PKR',\n 'PLN',\n 'PYG',\n 'QAR',\n 'RON',\n 'RSD',\n 'RUB',\n 'RWF',\n 'SAR',\n 'SBD',\n 'SCR',\n 'SEK',\n 'SGD',\n 'SHP',\n 'SLE',\n 'SLL',\n 'SOS',\n 'SRD',\n 'SSP',\n 'STN',\n 'SVC',\n 'SZL',\n 'THB',\n 'TND',\n 'TOP',\n 'TRY',\n 'TTD',\n 'TWD',\n 'TZS',\n 'UAH',\n 'UGX',\n 'USD',\n 'UYU',\n 'UZS',\n 'VES',\n 'VND',\n 'VUV',\n 'WST',\n 'XAF',\n 'XCD',\n 'XOF',\n 'XPF',\n 'YER',\n 'ZAR',\n 'ZMW'\n ]\n },\n tax_category: {\n type: 'string',\n description: 'Represents the different categories of taxation applicable to various products and services.',\n enum: [ 'digital_products',\n 'saas',\n 'e_book',\n 'edtech'\n ]\n }\n }\n}\n```",
22 | inputSchema: {
23 | type: 'object',
24 | properties: {
25 | currency: {
26 | $ref: '#/$defs/currency',
27 | },
28 | name: {
29 | type: 'string',
30 | description: 'Name of the Addon',
31 | },
32 | price: {
33 | type: 'integer',
34 | description: 'Amount of the addon',
35 | },
36 | tax_category: {
37 | $ref: '#/$defs/tax_category',
38 | },
39 | description: {
40 | type: 'string',
41 | description: 'Optional description of the Addon',
42 | },
43 | jq_filter: {
44 | type: 'string',
45 | title: 'jq Filter',
46 | description:
47 | 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
48 | },
49 | },
50 | required: ['currency', 'name', 'price', 'tax_category'],
51 | $defs: {
52 | currency: {
53 | type: 'string',
54 | enum: [
55 | 'AED',
56 | 'ALL',
57 | 'AMD',
58 | 'ANG',
59 | 'AOA',
60 | 'ARS',
61 | 'AUD',
62 | 'AWG',
63 | 'AZN',
64 | 'BAM',
65 | 'BBD',
66 | 'BDT',
67 | 'BGN',
68 | 'BHD',
69 | 'BIF',
70 | 'BMD',
71 | 'BND',
72 | 'BOB',
73 | 'BRL',
74 | 'BSD',
75 | 'BWP',
76 | 'BYN',
77 | 'BZD',
78 | 'CAD',
79 | 'CHF',
80 | 'CLP',
81 | 'CNY',
82 | 'COP',
83 | 'CRC',
84 | 'CUP',
85 | 'CVE',
86 | 'CZK',
87 | 'DJF',
88 | 'DKK',
89 | 'DOP',
90 | 'DZD',
91 | 'EGP',
92 | 'ETB',
93 | 'EUR',
94 | 'FJD',
95 | 'FKP',
96 | 'GBP',
97 | 'GEL',
98 | 'GHS',
99 | 'GIP',
100 | 'GMD',
101 | 'GNF',
102 | 'GTQ',
103 | 'GYD',
104 | 'HKD',
105 | 'HNL',
106 | 'HRK',
107 | 'HTG',
108 | 'HUF',
109 | 'IDR',
110 | 'ILS',
111 | 'INR',
112 | 'IQD',
113 | 'JMD',
114 | 'JOD',
115 | 'JPY',
116 | 'KES',
117 | 'KGS',
118 | 'KHR',
119 | 'KMF',
120 | 'KRW',
121 | 'KWD',
122 | 'KYD',
123 | 'KZT',
124 | 'LAK',
125 | 'LBP',
126 | 'LKR',
127 | 'LRD',
128 | 'LSL',
129 | 'LYD',
130 | 'MAD',
131 | 'MDL',
132 | 'MGA',
133 | 'MKD',
134 | 'MMK',
135 | 'MNT',
136 | 'MOP',
137 | 'MRU',
138 | 'MUR',
139 | 'MVR',
140 | 'MWK',
141 | 'MXN',
142 | 'MYR',
143 | 'MZN',
144 | 'NAD',
145 | 'NGN',
146 | 'NIO',
147 | 'NOK',
148 | 'NPR',
149 | 'NZD',
150 | 'OMR',
151 | 'PAB',
152 | 'PEN',
153 | 'PGK',
154 | 'PHP',
155 | 'PKR',
156 | 'PLN',
157 | 'PYG',
158 | 'QAR',
159 | 'RON',
160 | 'RSD',
161 | 'RUB',
162 | 'RWF',
163 | 'SAR',
164 | 'SBD',
165 | 'SCR',
166 | 'SEK',
167 | 'SGD',
168 | 'SHP',
169 | 'SLE',
170 | 'SLL',
171 | 'SOS',
172 | 'SRD',
173 | 'SSP',
174 | 'STN',
175 | 'SVC',
176 | 'SZL',
177 | 'THB',
178 | 'TND',
179 | 'TOP',
180 | 'TRY',
181 | 'TTD',
182 | 'TWD',
183 | 'TZS',
184 | 'UAH',
185 | 'UGX',
186 | 'USD',
187 | 'UYU',
188 | 'UZS',
189 | 'VES',
190 | 'VND',
191 | 'VUV',
192 | 'WST',
193 | 'XAF',
194 | 'XCD',
195 | 'XOF',
196 | 'XPF',
197 | 'YER',
198 | 'ZAR',
199 | 'ZMW',
200 | ],
201 | },
202 | tax_category: {
203 | type: 'string',
204 | description:
205 | 'Represents the different categories of taxation applicable to various products and services.',
206 | enum: ['digital_products', 'saas', 'e_book', 'edtech'],
207 | },
208 | },
209 | },
210 | annotations: {},
211 | };
212 |
213 | export const handler = async (client: DodoPayments, args: Record<string, unknown> | undefined) => {
214 | const { jq_filter, ...body } = args as any;
215 | return asTextContentResult(await maybeFilter(jq_filter, await client.addons.create(body)));
216 | };
217 |
218 | export default { metadata, tool, handler };
219 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/subscriptions/retrieve-usage-history-subscriptions.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { maybeFilter } from 'dodopayments-mcp/filtering';
4 | import { Metadata, asTextContentResult } from 'dodopayments-mcp/tools/types';
5 |
6 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
7 | import DodoPayments from 'dodopayments';
8 |
9 | export const metadata: Metadata = {
10 | resource: 'subscriptions',
11 | operation: 'read',
12 | tags: [],
13 | httpMethod: 'get',
14 | httpPath: '/subscriptions/{subscription_id}/usage-history',
15 | operationId: 'list_usage_history_handler',
16 | };
17 |
18 | export const tool: Tool = {
19 | name: 'retrieve_usage_history_subscriptions',
20 | description:
21 | "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nGet detailed usage history for a subscription that includes usage-based billing (metered components).\nThis endpoint provides insights into customer usage patterns and billing calculations over time.\n\n## What You'll Get:\n- **Billing periods**: Each item represents a billing cycle with start and end dates\n- **Meter usage**: Detailed breakdown of usage for each meter configured on the subscription\n- **Usage calculations**: Total units consumed, free threshold units, and chargeable units\n- **Historical tracking**: Complete audit trail of usage-based charges\n\n## Use Cases:\n- **Customer support**: Investigate billing questions and usage discrepancies\n- **Usage analytics**: Analyze customer consumption patterns over time\n- **Billing transparency**: Provide customers with detailed usage breakdowns\n- **Revenue optimization**: Identify usage trends to optimize pricing strategies\n\n## Filtering Options:\n- **Date range filtering**: Get usage history for specific time periods\n- **Meter-specific filtering**: Focus on usage for a particular meter\n- **Pagination**: Navigate through large usage histories efficiently\n\n## Important Notes:\n- Only returns data for subscriptions with usage-based (metered) components\n- Usage history is organized by billing periods (subscription cycles)\n- Free threshold units are calculated and displayed separately from chargeable units\n- Historical data is preserved even if meter configurations change\n\n## Example Query Patterns:\n- Get last 3 months: `?start_date=2024-01-01T00:00:00Z&end_date=2024-03-31T23:59:59Z`\n- Filter by meter: `?meter_id=mtr_api_requests`\n- Paginate results: `?page_size=20&page_number=1`\n- Recent usage: `?start_date=2024-03-01T00:00:00Z` (from March 1st to now)\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n items: {\n type: 'array',\n description: 'List of usage history items',\n items: {\n $ref: '#/$defs/subscription_retrieve_usage_history_response'\n }\n }\n },\n required: [ 'items'\n ],\n $defs: {\n subscription_retrieve_usage_history_response: {\n type: 'object',\n properties: {\n end_date: {\n type: 'string',\n description: 'End date of the billing period',\n format: 'date-time'\n },\n meters: {\n type: 'array',\n description: 'List of meters and their usage for this billing period',\n items: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Meter identifier'\n },\n chargeable_units: {\n type: 'string',\n description: 'Chargeable units (after free threshold) as string for precision'\n },\n consumed_units: {\n type: 'string',\n description: 'Total units consumed as string for precision'\n },\n currency: {\n $ref: '#/$defs/currency'\n },\n free_threshold: {\n type: 'integer',\n description: 'Free threshold units for this meter'\n },\n name: {\n type: 'string',\n description: 'Meter name'\n },\n price_per_unit: {\n type: 'string',\n description: 'Price per unit in string format for precision'\n },\n total_price: {\n type: 'integer',\n description: 'Total price charged for this meter in smallest currency unit (cents)'\n }\n },\n required: [ 'id',\n 'chargeable_units',\n 'consumed_units',\n 'currency',\n 'free_threshold',\n 'name',\n 'price_per_unit',\n 'total_price'\n ]\n }\n },\n start_date: {\n type: 'string',\n description: 'Start date of the billing period',\n format: 'date-time'\n }\n },\n required: [ 'end_date',\n 'meters',\n 'start_date'\n ]\n },\n currency: {\n type: 'string',\n enum: [ 'AED',\n 'ALL',\n 'AMD',\n 'ANG',\n 'AOA',\n 'ARS',\n 'AUD',\n 'AWG',\n 'AZN',\n 'BAM',\n 'BBD',\n 'BDT',\n 'BGN',\n 'BHD',\n 'BIF',\n 'BMD',\n 'BND',\n 'BOB',\n 'BRL',\n 'BSD',\n 'BWP',\n 'BYN',\n 'BZD',\n 'CAD',\n 'CHF',\n 'CLP',\n 'CNY',\n 'COP',\n 'CRC',\n 'CUP',\n 'CVE',\n 'CZK',\n 'DJF',\n 'DKK',\n 'DOP',\n 'DZD',\n 'EGP',\n 'ETB',\n 'EUR',\n 'FJD',\n 'FKP',\n 'GBP',\n 'GEL',\n 'GHS',\n 'GIP',\n 'GMD',\n 'GNF',\n 'GTQ',\n 'GYD',\n 'HKD',\n 'HNL',\n 'HRK',\n 'HTG',\n 'HUF',\n 'IDR',\n 'ILS',\n 'INR',\n 'IQD',\n 'JMD',\n 'JOD',\n 'JPY',\n 'KES',\n 'KGS',\n 'KHR',\n 'KMF',\n 'KRW',\n 'KWD',\n 'KYD',\n 'KZT',\n 'LAK',\n 'LBP',\n 'LKR',\n 'LRD',\n 'LSL',\n 'LYD',\n 'MAD',\n 'MDL',\n 'MGA',\n 'MKD',\n 'MMK',\n 'MNT',\n 'MOP',\n 'MRU',\n 'MUR',\n 'MVR',\n 'MWK',\n 'MXN',\n 'MYR',\n 'MZN',\n 'NAD',\n 'NGN',\n 'NIO',\n 'NOK',\n 'NPR',\n 'NZD',\n 'OMR',\n 'PAB',\n 'PEN',\n 'PGK',\n 'PHP',\n 'PKR',\n 'PLN',\n 'PYG',\n 'QAR',\n 'RON',\n 'RSD',\n 'RUB',\n 'RWF',\n 'SAR',\n 'SBD',\n 'SCR',\n 'SEK',\n 'SGD',\n 'SHP',\n 'SLE',\n 'SLL',\n 'SOS',\n 'SRD',\n 'SSP',\n 'STN',\n 'SVC',\n 'SZL',\n 'THB',\n 'TND',\n 'TOP',\n 'TRY',\n 'TTD',\n 'TWD',\n 'TZS',\n 'UAH',\n 'UGX',\n 'USD',\n 'UYU',\n 'UZS',\n 'VES',\n 'VND',\n 'VUV',\n 'WST',\n 'XAF',\n 'XCD',\n 'XOF',\n 'XPF',\n 'YER',\n 'ZAR',\n 'ZMW'\n ]\n }\n }\n}\n```",
22 | inputSchema: {
23 | type: 'object',
24 | properties: {
25 | subscription_id: {
26 | type: 'string',
27 | },
28 | end_date: {
29 | type: 'string',
30 | description: 'Filter by end date (inclusive)',
31 | format: 'date-time',
32 | },
33 | meter_id: {
34 | type: 'string',
35 | description: 'Filter by specific meter ID',
36 | },
37 | page_number: {
38 | type: 'integer',
39 | description: 'Page number (default: 0)',
40 | },
41 | page_size: {
42 | type: 'integer',
43 | description: 'Page size (default: 10, max: 100)',
44 | },
45 | start_date: {
46 | type: 'string',
47 | description: 'Filter by start date (inclusive)',
48 | format: 'date-time',
49 | },
50 | jq_filter: {
51 | type: 'string',
52 | title: 'jq Filter',
53 | description:
54 | 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
55 | },
56 | },
57 | required: ['subscription_id'],
58 | },
59 | annotations: {
60 | readOnlyHint: true,
61 | },
62 | };
63 |
64 | export const handler = async (client: DodoPayments, args: Record<string, unknown> | undefined) => {
65 | const { subscription_id, jq_filter, ...body } = args as any;
66 | const response = await client.subscriptions.retrieveUsageHistory(subscription_id, body).asResponse();
67 | return asTextContentResult(await maybeFilter(jq_filter, await response.json()));
68 | };
69 |
70 | export default { metadata, tool, handler };
71 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/addons/update-addons.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { maybeFilter } from 'dodopayments-mcp/filtering';
4 | import { Metadata, asTextContentResult } from 'dodopayments-mcp/tools/types';
5 |
6 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
7 | import DodoPayments from 'dodopayments';
8 |
9 | export const metadata: Metadata = {
10 | resource: 'addons',
11 | operation: 'write',
12 | tags: [],
13 | httpMethod: 'patch',
14 | httpPath: '/addons/{id}',
15 | operationId: 'patch_addon',
16 | };
17 |
18 | export const tool: Tool = {
19 | name: 'update_addons',
20 | description:
21 | "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\n\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/addon_response',\n $defs: {\n addon_response: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'id of the Addon'\n },\n business_id: {\n type: 'string',\n description: 'Unique identifier for the business to which the addon belongs.'\n },\n created_at: {\n type: 'string',\n description: 'Created time',\n format: 'date-time'\n },\n currency: {\n $ref: '#/$defs/currency'\n },\n name: {\n type: 'string',\n description: 'Name of the Addon'\n },\n price: {\n type: 'integer',\n description: 'Amount of the addon'\n },\n tax_category: {\n $ref: '#/$defs/tax_category'\n },\n updated_at: {\n type: 'string',\n description: 'Updated time',\n format: 'date-time'\n },\n description: {\n type: 'string',\n description: 'Optional description of the Addon'\n },\n image: {\n type: 'string',\n description: 'Image of the Addon'\n }\n },\n required: [ 'id',\n 'business_id',\n 'created_at',\n 'currency',\n 'name',\n 'price',\n 'tax_category',\n 'updated_at'\n ]\n },\n currency: {\n type: 'string',\n enum: [ 'AED',\n 'ALL',\n 'AMD',\n 'ANG',\n 'AOA',\n 'ARS',\n 'AUD',\n 'AWG',\n 'AZN',\n 'BAM',\n 'BBD',\n 'BDT',\n 'BGN',\n 'BHD',\n 'BIF',\n 'BMD',\n 'BND',\n 'BOB',\n 'BRL',\n 'BSD',\n 'BWP',\n 'BYN',\n 'BZD',\n 'CAD',\n 'CHF',\n 'CLP',\n 'CNY',\n 'COP',\n 'CRC',\n 'CUP',\n 'CVE',\n 'CZK',\n 'DJF',\n 'DKK',\n 'DOP',\n 'DZD',\n 'EGP',\n 'ETB',\n 'EUR',\n 'FJD',\n 'FKP',\n 'GBP',\n 'GEL',\n 'GHS',\n 'GIP',\n 'GMD',\n 'GNF',\n 'GTQ',\n 'GYD',\n 'HKD',\n 'HNL',\n 'HRK',\n 'HTG',\n 'HUF',\n 'IDR',\n 'ILS',\n 'INR',\n 'IQD',\n 'JMD',\n 'JOD',\n 'JPY',\n 'KES',\n 'KGS',\n 'KHR',\n 'KMF',\n 'KRW',\n 'KWD',\n 'KYD',\n 'KZT',\n 'LAK',\n 'LBP',\n 'LKR',\n 'LRD',\n 'LSL',\n 'LYD',\n 'MAD',\n 'MDL',\n 'MGA',\n 'MKD',\n 'MMK',\n 'MNT',\n 'MOP',\n 'MRU',\n 'MUR',\n 'MVR',\n 'MWK',\n 'MXN',\n 'MYR',\n 'MZN',\n 'NAD',\n 'NGN',\n 'NIO',\n 'NOK',\n 'NPR',\n 'NZD',\n 'OMR',\n 'PAB',\n 'PEN',\n 'PGK',\n 'PHP',\n 'PKR',\n 'PLN',\n 'PYG',\n 'QAR',\n 'RON',\n 'RSD',\n 'RUB',\n 'RWF',\n 'SAR',\n 'SBD',\n 'SCR',\n 'SEK',\n 'SGD',\n 'SHP',\n 'SLE',\n 'SLL',\n 'SOS',\n 'SRD',\n 'SSP',\n 'STN',\n 'SVC',\n 'SZL',\n 'THB',\n 'TND',\n 'TOP',\n 'TRY',\n 'TTD',\n 'TWD',\n 'TZS',\n 'UAH',\n 'UGX',\n 'USD',\n 'UYU',\n 'UZS',\n 'VES',\n 'VND',\n 'VUV',\n 'WST',\n 'XAF',\n 'XCD',\n 'XOF',\n 'XPF',\n 'YER',\n 'ZAR',\n 'ZMW'\n ]\n },\n tax_category: {\n type: 'string',\n description: 'Represents the different categories of taxation applicable to various products and services.',\n enum: [ 'digital_products',\n 'saas',\n 'e_book',\n 'edtech'\n ]\n }\n }\n}\n```",
22 | inputSchema: {
23 | type: 'object',
24 | properties: {
25 | id: {
26 | type: 'string',
27 | },
28 | currency: {
29 | $ref: '#/$defs/currency',
30 | },
31 | description: {
32 | type: 'string',
33 | description: 'Description of the Addon, optional and must be at most 1000 characters.',
34 | },
35 | image_id: {
36 | type: 'string',
37 | description: 'Addon image id after its uploaded to S3',
38 | },
39 | name: {
40 | type: 'string',
41 | description: 'Name of the Addon, optional and must be at most 100 characters.',
42 | },
43 | price: {
44 | type: 'integer',
45 | description: 'Amount of the addon',
46 | },
47 | tax_category: {
48 | $ref: '#/$defs/tax_category',
49 | },
50 | jq_filter: {
51 | type: 'string',
52 | title: 'jq Filter',
53 | description:
54 | 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).',
55 | },
56 | },
57 | required: ['id'],
58 | $defs: {
59 | currency: {
60 | type: 'string',
61 | enum: [
62 | 'AED',
63 | 'ALL',
64 | 'AMD',
65 | 'ANG',
66 | 'AOA',
67 | 'ARS',
68 | 'AUD',
69 | 'AWG',
70 | 'AZN',
71 | 'BAM',
72 | 'BBD',
73 | 'BDT',
74 | 'BGN',
75 | 'BHD',
76 | 'BIF',
77 | 'BMD',
78 | 'BND',
79 | 'BOB',
80 | 'BRL',
81 | 'BSD',
82 | 'BWP',
83 | 'BYN',
84 | 'BZD',
85 | 'CAD',
86 | 'CHF',
87 | 'CLP',
88 | 'CNY',
89 | 'COP',
90 | 'CRC',
91 | 'CUP',
92 | 'CVE',
93 | 'CZK',
94 | 'DJF',
95 | 'DKK',
96 | 'DOP',
97 | 'DZD',
98 | 'EGP',
99 | 'ETB',
100 | 'EUR',
101 | 'FJD',
102 | 'FKP',
103 | 'GBP',
104 | 'GEL',
105 | 'GHS',
106 | 'GIP',
107 | 'GMD',
108 | 'GNF',
109 | 'GTQ',
110 | 'GYD',
111 | 'HKD',
112 | 'HNL',
113 | 'HRK',
114 | 'HTG',
115 | 'HUF',
116 | 'IDR',
117 | 'ILS',
118 | 'INR',
119 | 'IQD',
120 | 'JMD',
121 | 'JOD',
122 | 'JPY',
123 | 'KES',
124 | 'KGS',
125 | 'KHR',
126 | 'KMF',
127 | 'KRW',
128 | 'KWD',
129 | 'KYD',
130 | 'KZT',
131 | 'LAK',
132 | 'LBP',
133 | 'LKR',
134 | 'LRD',
135 | 'LSL',
136 | 'LYD',
137 | 'MAD',
138 | 'MDL',
139 | 'MGA',
140 | 'MKD',
141 | 'MMK',
142 | 'MNT',
143 | 'MOP',
144 | 'MRU',
145 | 'MUR',
146 | 'MVR',
147 | 'MWK',
148 | 'MXN',
149 | 'MYR',
150 | 'MZN',
151 | 'NAD',
152 | 'NGN',
153 | 'NIO',
154 | 'NOK',
155 | 'NPR',
156 | 'NZD',
157 | 'OMR',
158 | 'PAB',
159 | 'PEN',
160 | 'PGK',
161 | 'PHP',
162 | 'PKR',
163 | 'PLN',
164 | 'PYG',
165 | 'QAR',
166 | 'RON',
167 | 'RSD',
168 | 'RUB',
169 | 'RWF',
170 | 'SAR',
171 | 'SBD',
172 | 'SCR',
173 | 'SEK',
174 | 'SGD',
175 | 'SHP',
176 | 'SLE',
177 | 'SLL',
178 | 'SOS',
179 | 'SRD',
180 | 'SSP',
181 | 'STN',
182 | 'SVC',
183 | 'SZL',
184 | 'THB',
185 | 'TND',
186 | 'TOP',
187 | 'TRY',
188 | 'TTD',
189 | 'TWD',
190 | 'TZS',
191 | 'UAH',
192 | 'UGX',
193 | 'USD',
194 | 'UYU',
195 | 'UZS',
196 | 'VES',
197 | 'VND',
198 | 'VUV',
199 | 'WST',
200 | 'XAF',
201 | 'XCD',
202 | 'XOF',
203 | 'XPF',
204 | 'YER',
205 | 'ZAR',
206 | 'ZMW',
207 | ],
208 | },
209 | tax_category: {
210 | type: 'string',
211 | description:
212 | 'Represents the different categories of taxation applicable to various products and services.',
213 | enum: ['digital_products', 'saas', 'e_book', 'edtech'],
214 | },
215 | },
216 | },
217 | annotations: {},
218 | };
219 |
220 | export const handler = async (client: DodoPayments, args: Record<string, unknown> | undefined) => {
221 | const { id, jq_filter, ...body } = args as any;
222 | return asTextContentResult(await maybeFilter(jq_filter, await client.addons.update(id, body)));
223 | };
224 |
225 | export default { metadata, tool, handler };
226 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { Metadata, Endpoint, HandlerFunction } from './types';
4 |
5 | export { Metadata, Endpoint, HandlerFunction };
6 |
7 | import create_checkout_sessions from './checkout-sessions/create-checkout-sessions';
8 | import retrieve_checkout_sessions from './checkout-sessions/retrieve-checkout-sessions';
9 | import create_payments from './payments/create-payments';
10 | import retrieve_payments from './payments/retrieve-payments';
11 | import list_payments from './payments/list-payments';
12 | import retrieve_line_items_payments from './payments/retrieve-line-items-payments';
13 | import create_subscriptions from './subscriptions/create-subscriptions';
14 | import retrieve_subscriptions from './subscriptions/retrieve-subscriptions';
15 | import update_subscriptions from './subscriptions/update-subscriptions';
16 | import list_subscriptions from './subscriptions/list-subscriptions';
17 | import change_plan_subscriptions from './subscriptions/change-plan-subscriptions';
18 | import charge_subscriptions from './subscriptions/charge-subscriptions';
19 | import retrieve_usage_history_subscriptions from './subscriptions/retrieve-usage-history-subscriptions';
20 | import retrieve_invoices_payments from './invoices/payments/retrieve-invoices-payments';
21 | import retrieve_refund_invoices_payments from './invoices/payments/retrieve-refund-invoices-payments';
22 | import activate_licenses from './licenses/activate-licenses';
23 | import deactivate_licenses from './licenses/deactivate-licenses';
24 | import validate_licenses from './licenses/validate-licenses';
25 | import retrieve_license_keys from './license-keys/retrieve-license-keys';
26 | import update_license_keys from './license-keys/update-license-keys';
27 | import list_license_keys from './license-keys/list-license-keys';
28 | import retrieve_license_key_instances from './license-key-instances/retrieve-license-key-instances';
29 | import update_license_key_instances from './license-key-instances/update-license-key-instances';
30 | import list_license_key_instances from './license-key-instances/list-license-key-instances';
31 | import create_customers from './customers/create-customers';
32 | import retrieve_customers from './customers/retrieve-customers';
33 | import update_customers from './customers/update-customers';
34 | import list_customers from './customers/list-customers';
35 | import create_customers_customer_portal from './customers/customer-portal/create-customers-customer-portal';
36 | import list_customers_wallets from './customers/wallets/list-customers-wallets';
37 | import create_wallets_customers_ledger_entries from './customers/wallets/ledger-entries/create-wallets-customers-ledger-entries';
38 | import list_wallets_customers_ledger_entries from './customers/wallets/ledger-entries/list-wallets-customers-ledger-entries';
39 | import create_refunds from './refunds/create-refunds';
40 | import retrieve_refunds from './refunds/retrieve-refunds';
41 | import list_refunds from './refunds/list-refunds';
42 | import retrieve_disputes from './disputes/retrieve-disputes';
43 | import list_disputes from './disputes/list-disputes';
44 | import list_payouts from './payouts/list-payouts';
45 | import create_products from './products/create-products';
46 | import retrieve_products from './products/retrieve-products';
47 | import update_products from './products/update-products';
48 | import list_products from './products/list-products';
49 | import archive_products from './products/archive-products';
50 | import unarchive_products from './products/unarchive-products';
51 | import update_files_products from './products/update-files-products';
52 | import update_products_images from './products/images/update-products-images';
53 | import list_supported_countries_misc from './misc/list-supported-countries-misc';
54 | import create_discounts from './discounts/create-discounts';
55 | import retrieve_discounts from './discounts/retrieve-discounts';
56 | import update_discounts from './discounts/update-discounts';
57 | import list_discounts from './discounts/list-discounts';
58 | import delete_discounts from './discounts/delete-discounts';
59 | import create_addons from './addons/create-addons';
60 | import retrieve_addons from './addons/retrieve-addons';
61 | import update_addons from './addons/update-addons';
62 | import list_addons from './addons/list-addons';
63 | import update_images_addons from './addons/update-images-addons';
64 | import create_brands from './brands/create-brands';
65 | import retrieve_brands from './brands/retrieve-brands';
66 | import update_brands from './brands/update-brands';
67 | import list_brands from './brands/list-brands';
68 | import update_images_brands from './brands/update-images-brands';
69 | import create_webhooks from './webhooks/create-webhooks';
70 | import retrieve_webhooks from './webhooks/retrieve-webhooks';
71 | import update_webhooks from './webhooks/update-webhooks';
72 | import list_webhooks from './webhooks/list-webhooks';
73 | import delete_webhooks from './webhooks/delete-webhooks';
74 | import retrieve_secret_webhooks from './webhooks/retrieve-secret-webhooks';
75 | import retrieve_webhooks_headers from './webhooks/headers/retrieve-webhooks-headers';
76 | import update_webhooks_headers from './webhooks/headers/update-webhooks-headers';
77 | import retrieve_usage_events from './usage-events/retrieve-usage-events';
78 | import list_usage_events from './usage-events/list-usage-events';
79 | import ingest_usage_events from './usage-events/ingest-usage-events';
80 | import create_meters from './meters/create-meters';
81 | import retrieve_meters from './meters/retrieve-meters';
82 | import list_meters from './meters/list-meters';
83 | import archive_meters from './meters/archive-meters';
84 | import unarchive_meters from './meters/unarchive-meters';
85 |
86 | export const endpoints: Endpoint[] = [];
87 |
88 | function addEndpoint(endpoint: Endpoint) {
89 | endpoints.push(endpoint);
90 | }
91 |
92 | addEndpoint(create_checkout_sessions);
93 | addEndpoint(retrieve_checkout_sessions);
94 | addEndpoint(create_payments);
95 | addEndpoint(retrieve_payments);
96 | addEndpoint(list_payments);
97 | addEndpoint(retrieve_line_items_payments);
98 | addEndpoint(create_subscriptions);
99 | addEndpoint(retrieve_subscriptions);
100 | addEndpoint(update_subscriptions);
101 | addEndpoint(list_subscriptions);
102 | addEndpoint(change_plan_subscriptions);
103 | addEndpoint(charge_subscriptions);
104 | addEndpoint(retrieve_usage_history_subscriptions);
105 | addEndpoint(retrieve_invoices_payments);
106 | addEndpoint(retrieve_refund_invoices_payments);
107 | addEndpoint(activate_licenses);
108 | addEndpoint(deactivate_licenses);
109 | addEndpoint(validate_licenses);
110 | addEndpoint(retrieve_license_keys);
111 | addEndpoint(update_license_keys);
112 | addEndpoint(list_license_keys);
113 | addEndpoint(retrieve_license_key_instances);
114 | addEndpoint(update_license_key_instances);
115 | addEndpoint(list_license_key_instances);
116 | addEndpoint(create_customers);
117 | addEndpoint(retrieve_customers);
118 | addEndpoint(update_customers);
119 | addEndpoint(list_customers);
120 | addEndpoint(create_customers_customer_portal);
121 | addEndpoint(list_customers_wallets);
122 | addEndpoint(create_wallets_customers_ledger_entries);
123 | addEndpoint(list_wallets_customers_ledger_entries);
124 | addEndpoint(create_refunds);
125 | addEndpoint(retrieve_refunds);
126 | addEndpoint(list_refunds);
127 | addEndpoint(retrieve_disputes);
128 | addEndpoint(list_disputes);
129 | addEndpoint(list_payouts);
130 | addEndpoint(create_products);
131 | addEndpoint(retrieve_products);
132 | addEndpoint(update_products);
133 | addEndpoint(list_products);
134 | addEndpoint(archive_products);
135 | addEndpoint(unarchive_products);
136 | addEndpoint(update_files_products);
137 | addEndpoint(update_products_images);
138 | addEndpoint(list_supported_countries_misc);
139 | addEndpoint(create_discounts);
140 | addEndpoint(retrieve_discounts);
141 | addEndpoint(update_discounts);
142 | addEndpoint(list_discounts);
143 | addEndpoint(delete_discounts);
144 | addEndpoint(create_addons);
145 | addEndpoint(retrieve_addons);
146 | addEndpoint(update_addons);
147 | addEndpoint(list_addons);
148 | addEndpoint(update_images_addons);
149 | addEndpoint(create_brands);
150 | addEndpoint(retrieve_brands);
151 | addEndpoint(update_brands);
152 | addEndpoint(list_brands);
153 | addEndpoint(update_images_brands);
154 | addEndpoint(create_webhooks);
155 | addEndpoint(retrieve_webhooks);
156 | addEndpoint(update_webhooks);
157 | addEndpoint(list_webhooks);
158 | addEndpoint(delete_webhooks);
159 | addEndpoint(retrieve_secret_webhooks);
160 | addEndpoint(retrieve_webhooks_headers);
161 | addEndpoint(update_webhooks_headers);
162 | addEndpoint(retrieve_usage_events);
163 | addEndpoint(list_usage_events);
164 | addEndpoint(ingest_usage_events);
165 | addEndpoint(create_meters);
166 | addEndpoint(retrieve_meters);
167 | addEndpoint(list_meters);
168 | addEndpoint(archive_meters);
169 | addEndpoint(unarchive_meters);
170 |
171 | export type Filter = {
172 | type: 'resource' | 'operation' | 'tag' | 'tool';
173 | op: 'include' | 'exclude';
174 | value: string;
175 | };
176 |
177 | export function query(filters: Filter[], endpoints: Endpoint[]): Endpoint[] {
178 | const allExcludes = filters.length > 0 && filters.every((filter) => filter.op === 'exclude');
179 | const unmatchedFilters = new Set(filters);
180 |
181 | const filtered = endpoints.filter((endpoint: Endpoint) => {
182 | let included = false || allExcludes;
183 |
184 | for (const filter of filters) {
185 | if (match(filter, endpoint)) {
186 | unmatchedFilters.delete(filter);
187 | included = filter.op === 'include';
188 | }
189 | }
190 |
191 | return included;
192 | });
193 |
194 | // Check if any filters didn't match
195 | const unmatched = Array.from(unmatchedFilters).filter((f) => f.type === 'tool' || f.type === 'resource');
196 | if (unmatched.length > 0) {
197 | throw new Error(
198 | `The following filters did not match any endpoints: ${unmatched
199 | .map((f) => `${f.type}=${f.value}`)
200 | .join(', ')}`,
201 | );
202 | }
203 |
204 | return filtered;
205 | }
206 |
207 | function match({ type, value }: Filter, endpoint: Endpoint): boolean {
208 | switch (type) {
209 | case 'resource': {
210 | const regexStr = '^' + normalizeResource(value).replace(/\*/g, '.*') + '$';
211 | const regex = new RegExp(regexStr);
212 | return regex.test(normalizeResource(endpoint.metadata.resource));
213 | }
214 | case 'operation':
215 | return endpoint.metadata.operation === value;
216 | case 'tag':
217 | return endpoint.metadata.tags.includes(value);
218 | case 'tool':
219 | return endpoint.tool.name === value;
220 | }
221 | }
222 |
223 | function normalizeResource(resource: string): string {
224 | return resource.toLowerCase().replace(/[^a-z.*\-_]*/g, '');
225 | }
226 |
```
--------------------------------------------------------------------------------
/MIGRATION.md:
--------------------------------------------------------------------------------
```markdown
1 | # Migration guide
2 |
3 | This guide outlines the changes and steps needed to migrate your codebase to the latest version of the Dodo Payments TypeScript SDK.
4 |
5 | The main changes are that the SDK now relies on the [builtin Web fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) instead of `node-fetch` and has zero dependencies.
6 |
7 | ## Migration CLI
8 |
9 | Most programs will only need minimal changes, but to assist there is a migration tool that will automatically update your code for the new version.
10 | To use it, upgrade the `dodopayments` package, then run `./node_modules/.bin/dodopayments migrate ./your/src/folders` to update your code.
11 | To preview the changes without writing them to disk, run the tool with `--dry`.
12 |
13 | ## Environment requirements
14 |
15 | The minimum supported runtime and tooling versions are now:
16 |
17 | - Node.js 20 LTS (Most recent non-EOL Node version)
18 | - TypeScript 4.9
19 | - Jest 28
20 |
21 | ## Breaking changes
22 |
23 | ### Web types for `withResponse`, `asResponse`, and `APIError.headers`
24 |
25 | Because we now use the builtin Web fetch API on all platforms, if you wrote code that used `withResponse` or `asResponse` and then accessed `node-fetch`-specific properties on the result, you will need to switch to standardized alternatives.
26 | For example, `body` is now a [Web `ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) rather than a [node `Readable`](https://nodejs.org/api/stream.html#readable-streams).
27 |
28 | ```ts
29 | // Before:
30 | const res = await client.example.retrieve('string/with/slash').asResponse();
31 | res.body.pipe(process.stdout);
32 |
33 | // After:
34 | import { Readable } from 'node:stream';
35 | const res = await client.example.retrieve('string/with/slash').asResponse();
36 | Readable.fromWeb(res.body).pipe(process.stdout);
37 | ```
38 |
39 | Additionally, the `headers` property on `APIError` objects is now an instance of the Web [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) class. It was previously defined as `Record<string, string | null | undefined>`.
40 |
41 | ### URI encoded path parameters
42 |
43 | Path params are now properly encoded by default. If you were manually encoding path parameters before giving them to the SDK, you must now stop doing that and pass the
44 | param without any encoding applied.
45 |
46 | For example:
47 |
48 | ```diff
49 | - client.example.retrieve(encodeURIComponent('string/with/slash'))
50 | + client.example.retrieve('string/with/slash') // retrieves /example/string%2Fwith%2Fslash
51 | ```
52 |
53 | Previously without the `encodeURIComponent()` call we would have used the path `/example/string/with/slash`; now we'll use `/example/string%2Fwith%2Fslash`.
54 |
55 | ### Removed request options overloads
56 |
57 | When making requests with no required body, query or header parameters, you must now explicitly pass `null`, `undefined` or an empty object `{}` to the params argument in order to customise request options.
58 |
59 | ```diff
60 | client.example.list();
61 | client.example.list({}, { headers: { ... } });
62 | client.example.list(null, { headers: { ... } });
63 | client.example.list(undefined, { headers: { ... } });
64 | - client.example.list({ headers: { ... } });
65 | + client.example.list({}, { headers: { ... } });
66 | ```
67 |
68 | This affects the following methods:
69 |
70 | - `client.payments.list()`
71 | - `client.subscriptions.list()`
72 | - `client.subscriptions.retrieveUsageHistory()`
73 | - `client.licenseKeys.list()`
74 | - `client.licenseKeyInstances.list()`
75 | - `client.customers.list()`
76 | - `client.customers.customerPortal.create()`
77 | - `client.customers.wallets.ledgerEntries.list()`
78 | - `client.refunds.list()`
79 | - `client.disputes.list()`
80 | - `client.payouts.list()`
81 | - `client.products.list()`
82 | - `client.products.images.update()`
83 | - `client.discounts.list()`
84 | - `client.addons.list()`
85 | - `client.webhooks.list()`
86 | - `client.usageEvents.list()`
87 | - `client.meters.list()`
88 |
89 | ### Removed `httpAgent` in favor of `fetchOptions`
90 |
91 | The `httpAgent` client option has been removed in favor of a [platform-specific `fetchOptions` property](https://github.com/dodopayments/dodopayments-typescript#fetch-options).
92 | This change was made as `httpAgent` relied on `node:http` agents which are not supported by any runtime's builtin fetch implementation.
93 |
94 | If you were using `httpAgent` for proxy support, check out the [new proxy documentation](https://github.com/dodopayments/dodopayments-typescript#configuring-proxies).
95 |
96 | Before:
97 |
98 | ```ts
99 | import DodoPayments from 'dodopayments';
100 | import http from 'http';
101 | import { HttpsProxyAgent } from 'https-proxy-agent';
102 |
103 | // Configure the default for all requests:
104 | const client = new DodoPayments({
105 | httpAgent: new HttpsProxyAgent(process.env.PROXY_URL),
106 | });
107 | ```
108 |
109 | After:
110 |
111 | ```ts
112 | import DodoPayments from 'dodopayments';
113 | import * as undici from 'undici';
114 |
115 | const proxyAgent = new undici.ProxyAgent(process.env.PROXY_URL);
116 | const client = new DodoPayments({
117 | fetchOptions: {
118 | dispatcher: proxyAgent,
119 | },
120 | });
121 | ```
122 |
123 | ### Changed exports
124 |
125 | #### Refactor of `dodopayments/core`, `error`, `pagination`, `resource` and `uploads`
126 |
127 | Much of the `dodopayments/core` file was intended to be internal-only but it was publicly accessible, as such it has been refactored and split up into internal and public files, with public-facing code moved to a new `core` folder and internal code moving to the private `internal` folder.
128 |
129 | At the same time, we moved some public-facing files which were previously at the top level into `core` to make the file structure cleaner and more clear:
130 |
131 | ```typescript
132 | // Before
133 | import 'dodopayments/error';
134 | import 'dodopayments/pagination';
135 | import 'dodopayments/resource';
136 | import 'dodopayments/uploads';
137 |
138 | // After
139 | import 'dodopayments/core/error';
140 | import 'dodopayments/core/pagination';
141 | import 'dodopayments/core/resource';
142 | import 'dodopayments/core/uploads';
143 | ```
144 |
145 | If you were relying on anything that was only exported from `dodopayments/core` and is also not accessible anywhere else, please open an issue and we'll consider adding it to the public API.
146 |
147 | #### Resource classes
148 |
149 | Previously under certain circumstances it was possible to import resource classes like `CheckoutSessions` directly from the root of the package. This was never valid at the type level and only worked in CommonJS files.
150 | Now you must always either reference them as static class properties or import them directly from the files in which they are defined.
151 |
152 | ```typescript
153 | // Before
154 | const { CheckoutSessions } = require('dodopayments');
155 |
156 | // After
157 | const { DodoPayments } = require('dodopayments');
158 | DodoPayments.CheckoutSessions; // or import directly from dodopayments/resources/checkout-sessions
159 | ```
160 |
161 | #### Cleaned up `uploads` exports
162 |
163 | As part of the `core` refactor, `dodopayments/uploads` was moved to `dodopayments/core/uploads`
164 | and the following exports were removed, as they were not intended to be a part of the public API:
165 |
166 | - `fileFromPath`
167 | - `BlobPart`
168 | - `BlobLike`
169 | - `FileLike`
170 | - `ResponseLike`
171 | - `isResponseLike`
172 | - `isBlobLike`
173 | - `isFileLike`
174 | - `isUploadable`
175 | - `isMultipartBody`
176 | - `maybeMultipartFormRequestOptions`
177 | - `multipartFormRequestOptions`
178 | - `createForm`
179 |
180 | Note that `Uploadable` & `toFile` **are** still exported:
181 |
182 | ```typescript
183 | import { type Uploadable, toFile } from 'dodopayments/core/uploads';
184 | ```
185 |
186 | #### `APIClient`
187 |
188 | The `APIClient` base client class has been removed as it is no longer needed. If you were importing this class then you must now import the main client class:
189 |
190 | ```typescript
191 | // Before
192 | import { APIClient } from 'dodopayments/core';
193 |
194 | // After
195 | import { DodoPayments } from 'dodopayments';
196 | ```
197 |
198 | ### File handling
199 |
200 | The deprecated `fileFromPath` helper has been removed in favor of native Node.js streams:
201 |
202 | ```ts
203 | // Before
204 | DodoPayments.fileFromPath('path/to/file');
205 |
206 | // After
207 | import fs from 'fs';
208 | fs.createReadStream('path/to/file');
209 | ```
210 |
211 | Note that this function previously only worked on Node.js. If you're using Bun, you can use [`Bun.file`](https://bun.sh/docs/api/file-io) instead.
212 |
213 | ### Shims removal
214 |
215 | Previously you could configure the types that the SDK used like this:
216 |
217 | ```ts
218 | // Tell TypeScript and the package to use the global Web fetch instead of node-fetch.
219 | import 'dodopayments/shims/web';
220 | import DodoPayments from 'dodopayments';
221 | ```
222 |
223 | The `dodopayments/shims` imports have been removed. Your global types must now be [correctly configured](#minimum-types-requirements).
224 |
225 | ### Pagination changes
226 |
227 | The `for await` syntax **is not affected**. This still works as-is:
228 |
229 | ```ts
230 | // Automatically fetches more pages as needed.
231 | for await (const paymentListResponse of client.payments.list()) {
232 | console.log(paymentListResponse);
233 | }
234 | ```
235 |
236 | The interface for manually paginating through list results has been simplified:
237 |
238 | ```ts
239 | // Before
240 | page.nextPageParams();
241 | page.nextPageInfo();
242 | // Required manually handling { url } | { params } type
243 |
244 | // After
245 | page.nextPageRequestOptions();
246 | ```
247 |
248 | #### Removed unnecessary classes
249 |
250 | Page classes for individual methods are now type aliases:
251 |
252 | ```ts
253 | // Before
254 | export class PaymentListResponsesDefaultPageNumberPagination extends DefaultPageNumberPagination<PaymentListResponse> {}
255 |
256 | // After
257 | export type PaymentListResponsesDefaultPageNumberPagination =
258 | DefaultPageNumberPagination<PaymentListResponse>;
259 | ```
260 |
261 | If you were importing these classes at runtime, you'll need to switch to importing the base class or only import them at the type-level.
262 |
263 | ### `dodopayments/src` directory removed
264 |
265 | Previously IDEs may have auto-completed imports from the `dodopayments/src` directory, however this
266 | directory was only included for an improved go-to-definition experience and should not have been used at runtime.
267 |
268 | If you have any `dodopayments/src/*` imports, you will need to replace them with `dodopayments/*`.
269 |
270 | ```ts
271 | // Before
272 | import DodoPayments from 'dodopayments/src';
273 |
274 | // After
275 | import DodoPayments from 'dodopayments';
276 | ```
277 |
278 | ## TypeScript troubleshooting
279 |
280 | When referencing the library after updating, you may encounter new type errors related to JS features like private properties or fetch classes like Request, Response, and Headers.
281 | To resolve these issues, configure your tsconfig.json and install the appropriate `@types` packages for your runtime environment using the guidelines below:
282 |
283 | ### Browsers
284 |
285 | `tsconfig.json`
286 |
287 | ```jsonc
288 | {
289 | "target": "ES2018", // note: we recommend ES2020 or higher
290 | "lib": ["DOM", "DOM.Iterable", "ES2018"]
291 | }
292 | ```
293 |
294 | ### Node.js
295 |
296 | `tsconfig.json`
297 |
298 | ```jsonc
299 | {
300 | "target": "ES2018" // note: we recommend ES2020 or higher
301 | }
302 | ```
303 |
304 | `package.json`
305 |
306 | ```json
307 | {
308 | "devDependencies": {
309 | "@types/node": ">= 20"
310 | }
311 | }
312 | ```
313 |
314 | ### Cloudflare Workers
315 |
316 | `tsconfig.json`
317 |
318 | ```jsonc
319 | {
320 | "target": "ES2018", // note: we recommend ES2020 or higher
321 | "lib": ["ES2020"], // <- needed by @cloudflare/workers-types
322 | "types": ["@cloudflare/workers-types"]
323 | }
324 | ```
325 |
326 | `package.json`
327 |
328 | ```json
329 | {
330 | "devDependencies": {
331 | "@cloudflare/workers-types": ">= 0.20221111.0"
332 | }
333 | }
334 | ```
335 |
336 | ### Bun
337 |
338 | `tsconfig.json`
339 |
340 | ```jsonc
341 | {
342 | "target": "ES2018" // note: we recommend ES2020 or higher
343 | }
344 | ```
345 |
346 | `package.json`
347 |
348 | ```json
349 | {
350 | "devDependencies": {
351 | "@types/bun": ">= 1.2.0"
352 | }
353 | }
354 | ```
355 |
```
--------------------------------------------------------------------------------
/src/resources/checkout-sessions.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { APIResource } from '../core/resource';
4 | import * as MiscAPI from './misc';
5 | import * as PaymentsAPI from './payments';
6 | import * as SubscriptionsAPI from './subscriptions';
7 | import { APIPromise } from '../core/api-promise';
8 | import { RequestOptions } from '../internal/request-options';
9 | import { path } from '../internal/utils/path';
10 |
11 | export class CheckoutSessions extends APIResource {
12 | create(body: CheckoutSessionCreateParams, options?: RequestOptions): APIPromise<CheckoutSessionResponse> {
13 | return this._client.post('/checkouts', { body, ...options });
14 | }
15 |
16 | retrieve(id: string, options?: RequestOptions): APIPromise<CheckoutSessionStatus> {
17 | return this._client.get(path`/checkouts/${id}`, options);
18 | }
19 | }
20 |
21 | export interface CheckoutSessionRequest {
22 | product_cart: Array<CheckoutSessionRequest.ProductCart>;
23 |
24 | /**
25 | * Customers will never see payment methods that are not in this list. However,
26 | * adding a method here does not guarantee customers will see it. Availability
27 | * still depends on other factors (e.g., customer location, merchant settings).
28 | *
29 | * Disclaimar: Always provide 'credit' and 'debit' as a fallback. If all payment
30 | * methods are unavailable, checkout session will fail.
31 | */
32 | allowed_payment_method_types?: Array<PaymentsAPI.PaymentMethodTypes> | null;
33 |
34 | /**
35 | * Billing address information for the session
36 | */
37 | billing_address?: CheckoutSessionRequest.BillingAddress | null;
38 |
39 | /**
40 | * This field is ingored if adaptive pricing is disabled
41 | */
42 | billing_currency?: MiscAPI.Currency | null;
43 |
44 | /**
45 | * If confirm is true, all the details will be finalized. If required data is
46 | * missing, an API error is thrown.
47 | */
48 | confirm?: boolean;
49 |
50 | /**
51 | * Customer details for the session
52 | */
53 | customer?: PaymentsAPI.CustomerRequest | null;
54 |
55 | /**
56 | * Customization for the checkout session page
57 | */
58 | customization?: CheckoutSessionRequest.Customization;
59 |
60 | discount_code?: string | null;
61 |
62 | feature_flags?: CheckoutSessionRequest.FeatureFlags;
63 |
64 | /**
65 | * Override merchant default 3DS behaviour for this session
66 | */
67 | force_3ds?: boolean | null;
68 |
69 | /**
70 | * Additional metadata associated with the payment. Defaults to empty if not
71 | * provided.
72 | */
73 | metadata?: { [key: string]: string } | null;
74 |
75 | /**
76 | * The url to redirect after payment failure or success.
77 | */
78 | return_url?: string | null;
79 |
80 | /**
81 | * Display saved payment methods of a returning customer False by default
82 | */
83 | show_saved_payment_methods?: boolean;
84 |
85 | subscription_data?: CheckoutSessionRequest.SubscriptionData | null;
86 | }
87 |
88 | export namespace CheckoutSessionRequest {
89 | export interface ProductCart {
90 | /**
91 | * unique id of the product
92 | */
93 | product_id: string;
94 |
95 | quantity: number;
96 |
97 | /**
98 | * only valid if product is a subscription
99 | */
100 | addons?: Array<SubscriptionsAPI.AttachAddon> | null;
101 |
102 | /**
103 | * Amount the customer pays if pay_what_you_want is enabled. If disabled then
104 | * amount will be ignored Represented in the lowest denomination of the currency
105 | * (e.g., cents for USD). For example, to charge $1.00, pass `100`. Only applicable
106 | * for one time payments
107 | *
108 | * If amount is not set for pay_what_you_want product, customer is allowed to
109 | * select the amount.
110 | */
111 | amount?: number | null;
112 | }
113 |
114 | /**
115 | * Billing address information for the session
116 | */
117 | export interface BillingAddress {
118 | /**
119 | * Two-letter ISO country code (ISO 3166-1 alpha-2)
120 | */
121 | country: MiscAPI.CountryCode;
122 |
123 | /**
124 | * City name
125 | */
126 | city?: string | null;
127 |
128 | /**
129 | * State or province name
130 | */
131 | state?: string | null;
132 |
133 | /**
134 | * Street address including house number and unit/apartment if applicable
135 | */
136 | street?: string | null;
137 |
138 | /**
139 | * Postal code or ZIP code
140 | */
141 | zipcode?: string | null;
142 | }
143 |
144 | /**
145 | * Customization for the checkout session page
146 | */
147 | export interface Customization {
148 | /**
149 | * Force the checkout interface to render in a specific language (e.g. `en`, `es`)
150 | */
151 | force_language?: string | null;
152 |
153 | /**
154 | * Show on demand tag
155 | *
156 | * Default is true
157 | */
158 | show_on_demand_tag?: boolean;
159 |
160 | /**
161 | * Show order details by default
162 | *
163 | * Default is true
164 | */
165 | show_order_details?: boolean;
166 |
167 | /**
168 | * Theme of the page
169 | *
170 | * Default is `System`.
171 | */
172 | theme?: 'dark' | 'light' | 'system';
173 | }
174 |
175 | export interface FeatureFlags {
176 | /**
177 | * if customer is allowed to change currency, set it to true
178 | *
179 | * Default is true
180 | */
181 | allow_currency_selection?: boolean;
182 |
183 | /**
184 | * If the customer is allowed to apply discount code, set it to true.
185 | *
186 | * Default is true
187 | */
188 | allow_discount_code?: boolean;
189 |
190 | /**
191 | * If phone number is collected from customer, set it to rue
192 | *
193 | * Default is true
194 | */
195 | allow_phone_number_collection?: boolean;
196 |
197 | /**
198 | * If the customer is allowed to add tax id, set it to true
199 | *
200 | * Default is true
201 | */
202 | allow_tax_id?: boolean;
203 |
204 | /**
205 | * Set to true if a new customer object should be created. By default email is used
206 | * to find an existing customer to attach the session to
207 | *
208 | * Default is false
209 | */
210 | always_create_new_customer?: boolean;
211 | }
212 |
213 | export interface SubscriptionData {
214 | on_demand?: SubscriptionsAPI.OnDemandSubscription | null;
215 |
216 | /**
217 | * Optional trial period in days If specified, this value overrides the trial
218 | * period set in the product's price Must be between 0 and 10000 days
219 | */
220 | trial_period_days?: number | null;
221 | }
222 | }
223 |
224 | export interface CheckoutSessionResponse {
225 | /**
226 | * Checkout url
227 | */
228 | checkout_url: string;
229 |
230 | /**
231 | * The ID of the created checkout session
232 | */
233 | session_id: string;
234 | }
235 |
236 | export interface CheckoutSessionStatus {
237 | /**
238 | * Id of the checkout session
239 | */
240 | id: string;
241 |
242 | /**
243 | * Created at timestamp
244 | */
245 | created_at: string;
246 |
247 | /**
248 | * Customer email: prefers payment's customer, falls back to session
249 | */
250 | customer_email?: string | null;
251 |
252 | /**
253 | * Customer name: prefers payment's customer, falls back to session
254 | */
255 | customer_name?: string | null;
256 |
257 | /**
258 | * Id of the payment created by the checkout sessions.
259 | *
260 | * Null if checkout sessions is still at the details collection stage.
261 | */
262 | payment_id?: string | null;
263 |
264 | /**
265 | * status of the payment.
266 | *
267 | * Null if checkout sessions is still at the details collection stage.
268 | */
269 | payment_status?: PaymentsAPI.IntentStatus | null;
270 | }
271 |
272 | export interface CheckoutSessionCreateParams {
273 | product_cart: Array<CheckoutSessionCreateParams.ProductCart>;
274 |
275 | /**
276 | * Customers will never see payment methods that are not in this list. However,
277 | * adding a method here does not guarantee customers will see it. Availability
278 | * still depends on other factors (e.g., customer location, merchant settings).
279 | *
280 | * Disclaimar: Always provide 'credit' and 'debit' as a fallback. If all payment
281 | * methods are unavailable, checkout session will fail.
282 | */
283 | allowed_payment_method_types?: Array<PaymentsAPI.PaymentMethodTypes> | null;
284 |
285 | /**
286 | * Billing address information for the session
287 | */
288 | billing_address?: CheckoutSessionCreateParams.BillingAddress | null;
289 |
290 | /**
291 | * This field is ingored if adaptive pricing is disabled
292 | */
293 | billing_currency?: MiscAPI.Currency | null;
294 |
295 | /**
296 | * If confirm is true, all the details will be finalized. If required data is
297 | * missing, an API error is thrown.
298 | */
299 | confirm?: boolean;
300 |
301 | /**
302 | * Customer details for the session
303 | */
304 | customer?: PaymentsAPI.CustomerRequest | null;
305 |
306 | /**
307 | * Customization for the checkout session page
308 | */
309 | customization?: CheckoutSessionCreateParams.Customization;
310 |
311 | discount_code?: string | null;
312 |
313 | feature_flags?: CheckoutSessionCreateParams.FeatureFlags;
314 |
315 | /**
316 | * Override merchant default 3DS behaviour for this session
317 | */
318 | force_3ds?: boolean | null;
319 |
320 | /**
321 | * Additional metadata associated with the payment. Defaults to empty if not
322 | * provided.
323 | */
324 | metadata?: { [key: string]: string } | null;
325 |
326 | /**
327 | * The url to redirect after payment failure or success.
328 | */
329 | return_url?: string | null;
330 |
331 | /**
332 | * Display saved payment methods of a returning customer False by default
333 | */
334 | show_saved_payment_methods?: boolean;
335 |
336 | subscription_data?: CheckoutSessionCreateParams.SubscriptionData | null;
337 | }
338 |
339 | export namespace CheckoutSessionCreateParams {
340 | export interface ProductCart {
341 | /**
342 | * unique id of the product
343 | */
344 | product_id: string;
345 |
346 | quantity: number;
347 |
348 | /**
349 | * only valid if product is a subscription
350 | */
351 | addons?: Array<SubscriptionsAPI.AttachAddon> | null;
352 |
353 | /**
354 | * Amount the customer pays if pay_what_you_want is enabled. If disabled then
355 | * amount will be ignored Represented in the lowest denomination of the currency
356 | * (e.g., cents for USD). For example, to charge $1.00, pass `100`. Only applicable
357 | * for one time payments
358 | *
359 | * If amount is not set for pay_what_you_want product, customer is allowed to
360 | * select the amount.
361 | */
362 | amount?: number | null;
363 | }
364 |
365 | /**
366 | * Billing address information for the session
367 | */
368 | export interface BillingAddress {
369 | /**
370 | * Two-letter ISO country code (ISO 3166-1 alpha-2)
371 | */
372 | country: MiscAPI.CountryCode;
373 |
374 | /**
375 | * City name
376 | */
377 | city?: string | null;
378 |
379 | /**
380 | * State or province name
381 | */
382 | state?: string | null;
383 |
384 | /**
385 | * Street address including house number and unit/apartment if applicable
386 | */
387 | street?: string | null;
388 |
389 | /**
390 | * Postal code or ZIP code
391 | */
392 | zipcode?: string | null;
393 | }
394 |
395 | /**
396 | * Customization for the checkout session page
397 | */
398 | export interface Customization {
399 | /**
400 | * Force the checkout interface to render in a specific language (e.g. `en`, `es`)
401 | */
402 | force_language?: string | null;
403 |
404 | /**
405 | * Show on demand tag
406 | *
407 | * Default is true
408 | */
409 | show_on_demand_tag?: boolean;
410 |
411 | /**
412 | * Show order details by default
413 | *
414 | * Default is true
415 | */
416 | show_order_details?: boolean;
417 |
418 | /**
419 | * Theme of the page
420 | *
421 | * Default is `System`.
422 | */
423 | theme?: 'dark' | 'light' | 'system';
424 | }
425 |
426 | export interface FeatureFlags {
427 | /**
428 | * if customer is allowed to change currency, set it to true
429 | *
430 | * Default is true
431 | */
432 | allow_currency_selection?: boolean;
433 |
434 | /**
435 | * If the customer is allowed to apply discount code, set it to true.
436 | *
437 | * Default is true
438 | */
439 | allow_discount_code?: boolean;
440 |
441 | /**
442 | * If phone number is collected from customer, set it to rue
443 | *
444 | * Default is true
445 | */
446 | allow_phone_number_collection?: boolean;
447 |
448 | /**
449 | * If the customer is allowed to add tax id, set it to true
450 | *
451 | * Default is true
452 | */
453 | allow_tax_id?: boolean;
454 |
455 | /**
456 | * Set to true if a new customer object should be created. By default email is used
457 | * to find an existing customer to attach the session to
458 | *
459 | * Default is false
460 | */
461 | always_create_new_customer?: boolean;
462 | }
463 |
464 | export interface SubscriptionData {
465 | on_demand?: SubscriptionsAPI.OnDemandSubscription | null;
466 |
467 | /**
468 | * Optional trial period in days If specified, this value overrides the trial
469 | * period set in the product's price Must be between 0 and 10000 days
470 | */
471 | trial_period_days?: number | null;
472 | }
473 | }
474 |
475 | export declare namespace CheckoutSessions {
476 | export {
477 | type CheckoutSessionRequest as CheckoutSessionRequest,
478 | type CheckoutSessionResponse as CheckoutSessionResponse,
479 | type CheckoutSessionStatus as CheckoutSessionStatus,
480 | type CheckoutSessionCreateParams as CheckoutSessionCreateParams,
481 | };
482 | }
483 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/tools/payments/create-payments.ts:
--------------------------------------------------------------------------------
```typescript
1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2 |
3 | import { Metadata, asTextContentResult } from 'dodopayments-mcp/tools/types';
4 |
5 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
6 | import DodoPayments from 'dodopayments';
7 |
8 | export const metadata: Metadata = {
9 | resource: 'payments',
10 | operation: 'write',
11 | tags: [],
12 | httpMethod: 'post',
13 | httpPath: '/payments',
14 | operationId: 'create_one_time_payment_handler',
15 | };
16 |
17 | export const tool: Tool = {
18 | name: 'create_payments',
19 | description: '',
20 | inputSchema: {
21 | type: 'object',
22 | properties: {
23 | billing: {
24 | $ref: '#/$defs/billing_address',
25 | },
26 | customer: {
27 | $ref: '#/$defs/customer_request',
28 | },
29 | product_cart: {
30 | type: 'array',
31 | description: 'List of products in the cart. Must contain at least 1 and at most 100 items.',
32 | items: {
33 | $ref: '#/$defs/one_time_product_cart_item',
34 | },
35 | },
36 | allowed_payment_method_types: {
37 | type: 'array',
38 | description:
39 | 'List of payment methods allowed during checkout.\n\nCustomers will **never** see payment methods that are **not** in this list.\nHowever, adding a method here **does not guarantee** customers will see it.\nAvailability still depends on other factors (e.g., customer location, merchant settings).',
40 | items: {
41 | $ref: '#/$defs/payment_method_types',
42 | },
43 | },
44 | billing_currency: {
45 | $ref: '#/$defs/currency',
46 | },
47 | discount_code: {
48 | type: 'string',
49 | description: 'Discount Code to apply to the transaction',
50 | },
51 | force_3ds: {
52 | type: 'boolean',
53 | description: 'Override merchant default 3DS behaviour for this payment',
54 | },
55 | metadata: {
56 | type: 'object',
57 | description: 'Additional metadata associated with the payment.\nDefaults to empty if not provided.',
58 | additionalProperties: true,
59 | },
60 | payment_link: {
61 | type: 'boolean',
62 | description: 'Whether to generate a payment link. Defaults to false if not specified.',
63 | },
64 | return_url: {
65 | type: 'string',
66 | description: 'Optional URL to redirect the customer after payment.\nMust be a valid URL if provided.',
67 | },
68 | show_saved_payment_methods: {
69 | type: 'boolean',
70 | description: 'Display saved payment methods of a returning customer\nFalse by default',
71 | },
72 | tax_id: {
73 | type: 'string',
74 | description:
75 | 'Tax ID in case the payment is B2B. If tax id validation fails the payment creation will fail',
76 | },
77 | },
78 | required: ['billing', 'customer', 'product_cart'],
79 | $defs: {
80 | billing_address: {
81 | type: 'object',
82 | properties: {
83 | city: {
84 | type: 'string',
85 | description: 'City name',
86 | },
87 | country: {
88 | $ref: '#/$defs/country_code',
89 | },
90 | state: {
91 | type: 'string',
92 | description: 'State or province name',
93 | },
94 | street: {
95 | type: 'string',
96 | description: 'Street address including house number and unit/apartment if applicable',
97 | },
98 | zipcode: {
99 | type: 'string',
100 | description: 'Postal code or ZIP code',
101 | },
102 | },
103 | required: ['city', 'country', 'state', 'street', 'zipcode'],
104 | },
105 | country_code: {
106 | type: 'string',
107 | description: 'ISO country code alpha2 variant',
108 | enum: [
109 | 'AF',
110 | 'AX',
111 | 'AL',
112 | 'DZ',
113 | 'AS',
114 | 'AD',
115 | 'AO',
116 | 'AI',
117 | 'AQ',
118 | 'AG',
119 | 'AR',
120 | 'AM',
121 | 'AW',
122 | 'AU',
123 | 'AT',
124 | 'AZ',
125 | 'BS',
126 | 'BH',
127 | 'BD',
128 | 'BB',
129 | 'BY',
130 | 'BE',
131 | 'BZ',
132 | 'BJ',
133 | 'BM',
134 | 'BT',
135 | 'BO',
136 | 'BQ',
137 | 'BA',
138 | 'BW',
139 | 'BV',
140 | 'BR',
141 | 'IO',
142 | 'BN',
143 | 'BG',
144 | 'BF',
145 | 'BI',
146 | 'KH',
147 | 'CM',
148 | 'CA',
149 | 'CV',
150 | 'KY',
151 | 'CF',
152 | 'TD',
153 | 'CL',
154 | 'CN',
155 | 'CX',
156 | 'CC',
157 | 'CO',
158 | 'KM',
159 | 'CG',
160 | 'CD',
161 | 'CK',
162 | 'CR',
163 | 'CI',
164 | 'HR',
165 | 'CU',
166 | 'CW',
167 | 'CY',
168 | 'CZ',
169 | 'DK',
170 | 'DJ',
171 | 'DM',
172 | 'DO',
173 | 'EC',
174 | 'EG',
175 | 'SV',
176 | 'GQ',
177 | 'ER',
178 | 'EE',
179 | 'ET',
180 | 'FK',
181 | 'FO',
182 | 'FJ',
183 | 'FI',
184 | 'FR',
185 | 'GF',
186 | 'PF',
187 | 'TF',
188 | 'GA',
189 | 'GM',
190 | 'GE',
191 | 'DE',
192 | 'GH',
193 | 'GI',
194 | 'GR',
195 | 'GL',
196 | 'GD',
197 | 'GP',
198 | 'GU',
199 | 'GT',
200 | 'GG',
201 | 'GN',
202 | 'GW',
203 | 'GY',
204 | 'HT',
205 | 'HM',
206 | 'VA',
207 | 'HN',
208 | 'HK',
209 | 'HU',
210 | 'IS',
211 | 'IN',
212 | 'ID',
213 | 'IR',
214 | 'IQ',
215 | 'IE',
216 | 'IM',
217 | 'IL',
218 | 'IT',
219 | 'JM',
220 | 'JP',
221 | 'JE',
222 | 'JO',
223 | 'KZ',
224 | 'KE',
225 | 'KI',
226 | 'KP',
227 | 'KR',
228 | 'KW',
229 | 'KG',
230 | 'LA',
231 | 'LV',
232 | 'LB',
233 | 'LS',
234 | 'LR',
235 | 'LY',
236 | 'LI',
237 | 'LT',
238 | 'LU',
239 | 'MO',
240 | 'MK',
241 | 'MG',
242 | 'MW',
243 | 'MY',
244 | 'MV',
245 | 'ML',
246 | 'MT',
247 | 'MH',
248 | 'MQ',
249 | 'MR',
250 | 'MU',
251 | 'YT',
252 | 'MX',
253 | 'FM',
254 | 'MD',
255 | 'MC',
256 | 'MN',
257 | 'ME',
258 | 'MS',
259 | 'MA',
260 | 'MZ',
261 | 'MM',
262 | 'NA',
263 | 'NR',
264 | 'NP',
265 | 'NL',
266 | 'NC',
267 | 'NZ',
268 | 'NI',
269 | 'NE',
270 | 'NG',
271 | 'NU',
272 | 'NF',
273 | 'MP',
274 | 'NO',
275 | 'OM',
276 | 'PK',
277 | 'PW',
278 | 'PS',
279 | 'PA',
280 | 'PG',
281 | 'PY',
282 | 'PE',
283 | 'PH',
284 | 'PN',
285 | 'PL',
286 | 'PT',
287 | 'PR',
288 | 'QA',
289 | 'RE',
290 | 'RO',
291 | 'RU',
292 | 'RW',
293 | 'BL',
294 | 'SH',
295 | 'KN',
296 | 'LC',
297 | 'MF',
298 | 'PM',
299 | 'VC',
300 | 'WS',
301 | 'SM',
302 | 'ST',
303 | 'SA',
304 | 'SN',
305 | 'RS',
306 | 'SC',
307 | 'SL',
308 | 'SG',
309 | 'SX',
310 | 'SK',
311 | 'SI',
312 | 'SB',
313 | 'SO',
314 | 'ZA',
315 | 'GS',
316 | 'SS',
317 | 'ES',
318 | 'LK',
319 | 'SD',
320 | 'SR',
321 | 'SJ',
322 | 'SZ',
323 | 'SE',
324 | 'CH',
325 | 'SY',
326 | 'TW',
327 | 'TJ',
328 | 'TZ',
329 | 'TH',
330 | 'TL',
331 | 'TG',
332 | 'TK',
333 | 'TO',
334 | 'TT',
335 | 'TN',
336 | 'TR',
337 | 'TM',
338 | 'TC',
339 | 'TV',
340 | 'UG',
341 | 'UA',
342 | 'AE',
343 | 'GB',
344 | 'UM',
345 | 'US',
346 | 'UY',
347 | 'UZ',
348 | 'VU',
349 | 'VE',
350 | 'VN',
351 | 'VG',
352 | 'VI',
353 | 'WF',
354 | 'EH',
355 | 'YE',
356 | 'ZM',
357 | 'ZW',
358 | ],
359 | },
360 | customer_request: {
361 | anyOf: [
362 | {
363 | $ref: '#/$defs/attach_existing_customer',
364 | },
365 | {
366 | $ref: '#/$defs/new_customer',
367 | },
368 | ],
369 | title: 'Customer Request',
370 | },
371 | attach_existing_customer: {
372 | type: 'object',
373 | title: 'Attach Existing Customer',
374 | properties: {
375 | customer_id: {
376 | type: 'string',
377 | },
378 | },
379 | required: ['customer_id'],
380 | },
381 | new_customer: {
382 | type: 'object',
383 | title: 'New Customer',
384 | properties: {
385 | email: {
386 | type: 'string',
387 | description: 'Email is required for creating a new customer',
388 | },
389 | name: {
390 | type: 'string',
391 | description:
392 | 'Optional full name of the customer. If provided during session creation,\nit is persisted and becomes immutable for the session. If omitted here,\nit can be provided later via the confirm API.',
393 | },
394 | phone_number: {
395 | type: 'string',
396 | },
397 | },
398 | required: ['email'],
399 | },
400 | one_time_product_cart_item: {
401 | type: 'object',
402 | title: 'One-Time Product Cart Item',
403 | properties: {
404 | product_id: {
405 | type: 'string',
406 | },
407 | quantity: {
408 | type: 'integer',
409 | },
410 | amount: {
411 | type: 'integer',
412 | description:
413 | 'Amount the customer pays if pay_what_you_want is enabled. If disabled then amount will be ignored\nRepresented in the lowest denomination of the currency (e.g., cents for USD).\nFor example, to charge $1.00, pass `100`.',
414 | },
415 | },
416 | required: ['product_id', 'quantity'],
417 | },
418 | payment_method_types: {
419 | type: 'string',
420 | enum: [
421 | 'credit',
422 | 'debit',
423 | 'upi_collect',
424 | 'upi_intent',
425 | 'apple_pay',
426 | 'cashapp',
427 | 'google_pay',
428 | 'multibanco',
429 | 'bancontact_card',
430 | 'eps',
431 | 'ideal',
432 | 'przelewy24',
433 | 'paypal',
434 | 'affirm',
435 | 'klarna',
436 | 'sepa',
437 | 'ach',
438 | 'amazon_pay',
439 | 'afterpay_clearpay',
440 | ],
441 | },
442 | currency: {
443 | type: 'string',
444 | enum: [
445 | 'AED',
446 | 'ALL',
447 | 'AMD',
448 | 'ANG',
449 | 'AOA',
450 | 'ARS',
451 | 'AUD',
452 | 'AWG',
453 | 'AZN',
454 | 'BAM',
455 | 'BBD',
456 | 'BDT',
457 | 'BGN',
458 | 'BHD',
459 | 'BIF',
460 | 'BMD',
461 | 'BND',
462 | 'BOB',
463 | 'BRL',
464 | 'BSD',
465 | 'BWP',
466 | 'BYN',
467 | 'BZD',
468 | 'CAD',
469 | 'CHF',
470 | 'CLP',
471 | 'CNY',
472 | 'COP',
473 | 'CRC',
474 | 'CUP',
475 | 'CVE',
476 | 'CZK',
477 | 'DJF',
478 | 'DKK',
479 | 'DOP',
480 | 'DZD',
481 | 'EGP',
482 | 'ETB',
483 | 'EUR',
484 | 'FJD',
485 | 'FKP',
486 | 'GBP',
487 | 'GEL',
488 | 'GHS',
489 | 'GIP',
490 | 'GMD',
491 | 'GNF',
492 | 'GTQ',
493 | 'GYD',
494 | 'HKD',
495 | 'HNL',
496 | 'HRK',
497 | 'HTG',
498 | 'HUF',
499 | 'IDR',
500 | 'ILS',
501 | 'INR',
502 | 'IQD',
503 | 'JMD',
504 | 'JOD',
505 | 'JPY',
506 | 'KES',
507 | 'KGS',
508 | 'KHR',
509 | 'KMF',
510 | 'KRW',
511 | 'KWD',
512 | 'KYD',
513 | 'KZT',
514 | 'LAK',
515 | 'LBP',
516 | 'LKR',
517 | 'LRD',
518 | 'LSL',
519 | 'LYD',
520 | 'MAD',
521 | 'MDL',
522 | 'MGA',
523 | 'MKD',
524 | 'MMK',
525 | 'MNT',
526 | 'MOP',
527 | 'MRU',
528 | 'MUR',
529 | 'MVR',
530 | 'MWK',
531 | 'MXN',
532 | 'MYR',
533 | 'MZN',
534 | 'NAD',
535 | 'NGN',
536 | 'NIO',
537 | 'NOK',
538 | 'NPR',
539 | 'NZD',
540 | 'OMR',
541 | 'PAB',
542 | 'PEN',
543 | 'PGK',
544 | 'PHP',
545 | 'PKR',
546 | 'PLN',
547 | 'PYG',
548 | 'QAR',
549 | 'RON',
550 | 'RSD',
551 | 'RUB',
552 | 'RWF',
553 | 'SAR',
554 | 'SBD',
555 | 'SCR',
556 | 'SEK',
557 | 'SGD',
558 | 'SHP',
559 | 'SLE',
560 | 'SLL',
561 | 'SOS',
562 | 'SRD',
563 | 'SSP',
564 | 'STN',
565 | 'SVC',
566 | 'SZL',
567 | 'THB',
568 | 'TND',
569 | 'TOP',
570 | 'TRY',
571 | 'TTD',
572 | 'TWD',
573 | 'TZS',
574 | 'UAH',
575 | 'UGX',
576 | 'USD',
577 | 'UYU',
578 | 'UZS',
579 | 'VES',
580 | 'VND',
581 | 'VUV',
582 | 'WST',
583 | 'XAF',
584 | 'XCD',
585 | 'XOF',
586 | 'XPF',
587 | 'YER',
588 | 'ZAR',
589 | 'ZMW',
590 | ],
591 | },
592 | },
593 | },
594 | annotations: {},
595 | };
596 |
597 | export const handler = async (client: DodoPayments, args: Record<string, unknown> | undefined) => {
598 | const body = args as any;
599 | return asTextContentResult(await client.payments.create(body));
600 | };
601 |
602 | export default { metadata, tool, handler };
603 |
```
--------------------------------------------------------------------------------
/packages/mcp-server/src/compat.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
2 | import { z } from 'zod';
3 | import { Endpoint } from './tools';
4 |
5 | export interface ClientCapabilities {
6 | topLevelUnions: boolean;
7 | validJson: boolean;
8 | refs: boolean;
9 | unions: boolean;
10 | formats: boolean;
11 | toolNameLength: number | undefined;
12 | }
13 |
14 | export const defaultClientCapabilities: ClientCapabilities = {
15 | topLevelUnions: true,
16 | validJson: true,
17 | refs: true,
18 | unions: true,
19 | formats: true,
20 | toolNameLength: undefined,
21 | };
22 |
23 | export const ClientType = z.enum(['openai-agents', 'claude', 'claude-code', 'cursor', 'infer']);
24 | export type ClientType = z.infer<typeof ClientType>;
25 |
26 | // Client presets for compatibility
27 | // Note that these could change over time as models get better, so this is
28 | // a best effort.
29 | export const knownClients: Record<Exclude<ClientType, 'infer'>, ClientCapabilities> = {
30 | 'openai-agents': {
31 | topLevelUnions: false,
32 | validJson: true,
33 | refs: true,
34 | unions: true,
35 | formats: true,
36 | toolNameLength: undefined,
37 | },
38 | claude: {
39 | topLevelUnions: true,
40 | validJson: false,
41 | refs: true,
42 | unions: true,
43 | formats: true,
44 | toolNameLength: undefined,
45 | },
46 | 'claude-code': {
47 | topLevelUnions: false,
48 | validJson: true,
49 | refs: true,
50 | unions: true,
51 | formats: true,
52 | toolNameLength: undefined,
53 | },
54 | cursor: {
55 | topLevelUnions: false,
56 | validJson: true,
57 | refs: false,
58 | unions: false,
59 | formats: false,
60 | toolNameLength: 50,
61 | },
62 | };
63 |
64 | /**
65 | * Attempts to parse strings into JSON objects
66 | */
67 | export function parseEmbeddedJSON(args: Record<string, unknown>, schema: Record<string, unknown>) {
68 | let updated = false;
69 | const newArgs: Record<string, unknown> = Object.assign({}, args);
70 |
71 | for (const [key, value] of Object.entries(newArgs)) {
72 | if (typeof value === 'string') {
73 | try {
74 | const parsed = JSON.parse(value);
75 | // Only parse if result is a plain object (not array, null, or primitive)
76 | if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
77 | newArgs[key] = parsed;
78 | updated = true;
79 | }
80 | } catch (e) {
81 | // Not valid JSON, leave as is
82 | }
83 | }
84 | }
85 |
86 | if (updated) {
87 | return newArgs;
88 | }
89 |
90 | return args;
91 | }
92 |
93 | export type JSONSchema = {
94 | type?: string;
95 | properties?: Record<string, JSONSchema>;
96 | required?: string[];
97 | anyOf?: JSONSchema[];
98 | $ref?: string;
99 | $defs?: Record<string, JSONSchema>;
100 | [key: string]: any;
101 | };
102 |
103 | /**
104 | * Truncates tool names to the specified length while ensuring uniqueness.
105 | * If truncation would cause duplicate names, appends a number to make them unique.
106 | */
107 | export function truncateToolNames(names: string[], maxLength: number): Map<string, string> {
108 | if (maxLength <= 0) {
109 | return new Map();
110 | }
111 |
112 | const renameMap = new Map<string, string>();
113 | const usedNames = new Set<string>();
114 |
115 | const toTruncate = names.filter((name) => name.length > maxLength);
116 |
117 | if (toTruncate.length === 0) {
118 | return renameMap;
119 | }
120 |
121 | const willCollide =
122 | new Set(toTruncate.map((name) => name.slice(0, maxLength - 1))).size < toTruncate.length;
123 |
124 | if (!willCollide) {
125 | for (const name of toTruncate) {
126 | const truncatedName = name.slice(0, maxLength);
127 | renameMap.set(name, truncatedName);
128 | }
129 | } else {
130 | const baseLength = maxLength - 1;
131 |
132 | for (const name of toTruncate) {
133 | const baseName = name.slice(0, baseLength);
134 | let counter = 1;
135 |
136 | while (usedNames.has(baseName + counter)) {
137 | counter++;
138 | }
139 |
140 | const finalName = baseName + counter;
141 | renameMap.set(name, finalName);
142 | usedNames.add(finalName);
143 | }
144 | }
145 |
146 | return renameMap;
147 | }
148 |
149 | /**
150 | * Removes top-level unions from a tool by splitting it into multiple tools,
151 | * one for each variant in the union.
152 | */
153 | export function removeTopLevelUnions(tool: Tool): Tool[] {
154 | const inputSchema = tool.inputSchema as JSONSchema;
155 | const variants = inputSchema.anyOf;
156 |
157 | if (!variants || !Array.isArray(variants) || variants.length === 0) {
158 | return [tool];
159 | }
160 |
161 | const defs = inputSchema.$defs || {};
162 |
163 | return variants.map((variant, index) => {
164 | const variantSchema: JSONSchema = {
165 | ...inputSchema,
166 | ...variant,
167 | type: 'object',
168 | properties: {
169 | ...(inputSchema.properties || {}),
170 | ...(variant.properties || {}),
171 | },
172 | };
173 |
174 | delete variantSchema.anyOf;
175 |
176 | if (!variantSchema['description']) {
177 | variantSchema['description'] = tool.description;
178 | }
179 |
180 | const usedDefs = findUsedDefs(variant, defs);
181 | if (Object.keys(usedDefs).length > 0) {
182 | variantSchema.$defs = usedDefs;
183 | } else {
184 | delete variantSchema.$defs;
185 | }
186 |
187 | return {
188 | ...tool,
189 | name: `${tool.name}_${toSnakeCase(variant['title'] || `variant${index + 1}`)}`,
190 | description: variant['description'] || tool.description,
191 | inputSchema: variantSchema,
192 | } as Tool;
193 | });
194 | }
195 |
196 | function findUsedDefs(
197 | schema: JSONSchema,
198 | defs: Record<string, JSONSchema>,
199 | visited: Set<string> = new Set(),
200 | ): Record<string, JSONSchema> {
201 | const usedDefs: Record<string, JSONSchema> = {};
202 |
203 | if (typeof schema !== 'object' || schema === null) {
204 | return usedDefs;
205 | }
206 |
207 | if (schema.$ref) {
208 | const refParts = schema.$ref.split('/');
209 | if (refParts[0] === '#' && refParts[1] === '$defs' && refParts[2]) {
210 | const defName = refParts[2];
211 | const def = defs[defName];
212 | if (def && !visited.has(schema.$ref)) {
213 | usedDefs[defName] = def;
214 | visited.add(schema.$ref);
215 | Object.assign(usedDefs, findUsedDefs(def, defs, visited));
216 | visited.delete(schema.$ref);
217 | }
218 | }
219 | return usedDefs;
220 | }
221 |
222 | for (const key in schema) {
223 | if (key !== '$defs' && typeof schema[key] === 'object' && schema[key] !== null) {
224 | Object.assign(usedDefs, findUsedDefs(schema[key] as JSONSchema, defs, visited));
225 | }
226 | }
227 |
228 | return usedDefs;
229 | }
230 |
231 | // Export for testing
232 | export { findUsedDefs };
233 |
234 | /**
235 | * Inlines all $refs in a schema, eliminating $defs.
236 | * If a circular reference is detected, the circular property is removed.
237 | */
238 | export function inlineRefs(schema: JSONSchema): JSONSchema {
239 | if (!schema || typeof schema !== 'object') {
240 | return schema;
241 | }
242 |
243 | const clonedSchema = { ...schema };
244 | const defs: Record<string, JSONSchema> = schema.$defs || {};
245 |
246 | delete clonedSchema.$defs;
247 |
248 | const result = inlineRefsRecursive(clonedSchema, defs, new Set<string>());
249 | // The top level can never be null
250 | return result === null ? {} : result;
251 | }
252 |
253 | function inlineRefsRecursive(
254 | schema: JSONSchema,
255 | defs: Record<string, JSONSchema>,
256 | refPath: Set<string>,
257 | ): JSONSchema | null {
258 | if (!schema || typeof schema !== 'object') {
259 | return schema;
260 | }
261 |
262 | if (Array.isArray(schema)) {
263 | return schema.map((item) => {
264 | const processed = inlineRefsRecursive(item, defs, refPath);
265 | return processed === null ? {} : processed;
266 | }) as JSONSchema;
267 | }
268 |
269 | const result = { ...schema };
270 |
271 | if ('$ref' in result && typeof result.$ref === 'string') {
272 | if (result.$ref.startsWith('#/$defs/')) {
273 | const refName = result.$ref.split('/').pop() as string;
274 | const def = defs[refName];
275 |
276 | // If we've already seen this ref in our path, we have a circular reference
277 | if (refPath.has(result.$ref)) {
278 | // For circular references, we completely remove the property
279 | // by returning null. The parent will remove it.
280 | return null;
281 | }
282 |
283 | if (def) {
284 | const newRefPath = new Set(refPath);
285 | newRefPath.add(result.$ref);
286 |
287 | const inlinedDef = inlineRefsRecursive({ ...def }, defs, newRefPath);
288 |
289 | if (inlinedDef === null) {
290 | return { ...result };
291 | }
292 |
293 | // Merge the inlined definition with the original schema's properties
294 | // but preserve things like description, etc.
295 | const { $ref, ...rest } = result;
296 | return { ...inlinedDef, ...rest };
297 | }
298 | }
299 |
300 | // Keep external refs as-is
301 | return result;
302 | }
303 |
304 | for (const key in result) {
305 | if (result[key] && typeof result[key] === 'object') {
306 | const processed = inlineRefsRecursive(result[key] as JSONSchema, defs, refPath);
307 | if (processed === null) {
308 | // Remove properties that would cause circular references
309 | delete result[key];
310 | } else {
311 | result[key] = processed;
312 | }
313 | }
314 | }
315 |
316 | return result;
317 | }
318 |
319 | /**
320 | * Removes anyOf fields from a schema, using only the first variant.
321 | */
322 | export function removeAnyOf(schema: JSONSchema): JSONSchema {
323 | if (!schema || typeof schema !== 'object') {
324 | return schema;
325 | }
326 |
327 | if (Array.isArray(schema)) {
328 | return schema.map((item) => removeAnyOf(item)) as JSONSchema;
329 | }
330 |
331 | const result = { ...schema };
332 |
333 | if ('anyOf' in result && Array.isArray(result.anyOf) && result.anyOf.length > 0) {
334 | const firstVariant = result.anyOf[0];
335 |
336 | if (firstVariant && typeof firstVariant === 'object') {
337 | // Special handling for properties to ensure deep merge
338 | if (firstVariant.properties && result.properties) {
339 | result.properties = {
340 | ...result.properties,
341 | ...(firstVariant.properties as Record<string, JSONSchema>),
342 | };
343 | } else if (firstVariant.properties) {
344 | result.properties = { ...firstVariant.properties };
345 | }
346 |
347 | for (const key in firstVariant) {
348 | if (key !== 'properties') {
349 | result[key] = firstVariant[key];
350 | }
351 | }
352 | }
353 |
354 | delete result.anyOf;
355 | }
356 |
357 | for (const key in result) {
358 | if (result[key] && typeof result[key] === 'object') {
359 | result[key] = removeAnyOf(result[key] as JSONSchema);
360 | }
361 | }
362 |
363 | return result;
364 | }
365 |
366 | /**
367 | * Removes format fields from a schema and appends them to the description.
368 | */
369 | export function removeFormats(schema: JSONSchema, formatsCapability: boolean): JSONSchema {
370 | if (formatsCapability) {
371 | return schema;
372 | }
373 |
374 | if (!schema || typeof schema !== 'object') {
375 | return schema;
376 | }
377 |
378 | if (Array.isArray(schema)) {
379 | return schema.map((item) => removeFormats(item, formatsCapability)) as JSONSchema;
380 | }
381 |
382 | const result = { ...schema };
383 |
384 | if ('format' in result && typeof result['format'] === 'string') {
385 | const formatStr = `(format: "${result['format']}")`;
386 |
387 | if ('description' in result && typeof result['description'] === 'string') {
388 | result['description'] = `${result['description']} ${formatStr}`;
389 | } else {
390 | result['description'] = formatStr;
391 | }
392 |
393 | delete result['format'];
394 | }
395 |
396 | for (const key in result) {
397 | if (result[key] && typeof result[key] === 'object') {
398 | result[key] = removeFormats(result[key] as JSONSchema, formatsCapability);
399 | }
400 | }
401 |
402 | return result;
403 | }
404 |
405 | /**
406 | * Applies all compatibility transformations to the endpoints based on the provided capabilities.
407 | */
408 | export function applyCompatibilityTransformations(
409 | endpoints: Endpoint[],
410 | capabilities: ClientCapabilities,
411 | ): Endpoint[] {
412 | let transformedEndpoints = [...endpoints];
413 |
414 | // Handle top-level unions first as this changes tool names
415 | if (!capabilities.topLevelUnions) {
416 | const newEndpoints: Endpoint[] = [];
417 |
418 | for (const endpoint of transformedEndpoints) {
419 | const variantTools = removeTopLevelUnions(endpoint.tool);
420 |
421 | if (variantTools.length === 1) {
422 | newEndpoints.push(endpoint);
423 | } else {
424 | for (const variantTool of variantTools) {
425 | newEndpoints.push({
426 | ...endpoint,
427 | tool: variantTool,
428 | });
429 | }
430 | }
431 | }
432 |
433 | transformedEndpoints = newEndpoints;
434 | }
435 |
436 | if (capabilities.toolNameLength) {
437 | const toolNames = transformedEndpoints.map((endpoint) => endpoint.tool.name);
438 | const renameMap = truncateToolNames(toolNames, capabilities.toolNameLength);
439 |
440 | transformedEndpoints = transformedEndpoints.map((endpoint) => ({
441 | ...endpoint,
442 | tool: {
443 | ...endpoint.tool,
444 | name: renameMap.get(endpoint.tool.name) ?? endpoint.tool.name,
445 | },
446 | }));
447 | }
448 |
449 | if (!capabilities.refs || !capabilities.unions || !capabilities.formats) {
450 | transformedEndpoints = transformedEndpoints.map((endpoint) => {
451 | let schema = endpoint.tool.inputSchema as JSONSchema;
452 |
453 | if (!capabilities.refs) {
454 | schema = inlineRefs(schema);
455 | }
456 |
457 | if (!capabilities.unions) {
458 | schema = removeAnyOf(schema);
459 | }
460 |
461 | if (!capabilities.formats) {
462 | schema = removeFormats(schema, capabilities.formats);
463 | }
464 |
465 | return {
466 | ...endpoint,
467 | tool: {
468 | ...endpoint.tool,
469 | inputSchema: schema as typeof endpoint.tool.inputSchema,
470 | },
471 | };
472 | });
473 | }
474 |
475 | return transformedEndpoints;
476 | }
477 |
478 | function toSnakeCase(str: string): string {
479 | return str
480 | .replace(/\s+/g, '_')
481 | .replace(/([a-z])([A-Z])/g, '$1_$2')
482 | .toLowerCase();
483 | }
484 |
```