#
tokens: 49615/50000 140/192 files (page 1/4)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 4. Use http://codebase.md/stripe/agent-toolkit?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .github
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   └── feature_request.yml
│   └── workflows
│       ├── main.yml
│       ├── npm_agent_toolkit_release.yml
│       ├── npm_mcp_release.yml
│       └── pypi_release.yml
├── .gitignore
├── .vscode
│   ├── extensions.json
│   ├── launch.json
│   └── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── evals
│   ├── .env.example
│   ├── .gitignore
│   ├── braintrust_openai.ts
│   ├── cases.ts
│   ├── eval.ts
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── README.md
│   ├── scorer.ts
│   └── tsconfig.json
├── gemini-extension.json
├── LICENSE
├── modelcontextprotocol
│   ├── .dxtignore
│   ├── .gitignore
│   ├── .node-version
│   ├── .prettierrc
│   ├── build-dxt.js
│   ├── Dockerfile
│   ├── eslint.config.mjs
│   ├── jest.config.ts
│   ├── manifest.json
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── README.md
│   ├── src
│   │   ├── index.ts
│   │   └── test
│   │       └── index.test.ts
│   ├── stripe_icon.png
│   └── tsconfig.json
├── python
│   ├── .editorconfig
│   ├── .flake8
│   ├── examples
│   │   ├── crewai
│   │   │   ├── .env.template
│   │   │   ├── main.py
│   │   │   └── README.md
│   │   ├── langchain
│   │   │   ├── __init__.py
│   │   │   ├── .env.template
│   │   │   ├── main.py
│   │   │   └── README.md
│   │   ├── openai
│   │   │   ├── .env.template
│   │   │   ├── customer_support
│   │   │   │   ├── .env.template
│   │   │   │   ├── emailer.py
│   │   │   │   ├── env.py
│   │   │   │   ├── main.py
│   │   │   │   ├── pyproject.toml
│   │   │   │   ├── README.md
│   │   │   │   ├── repl.py
│   │   │   │   └── support_agent.py
│   │   │   ├── file_search
│   │   │   │   ├── main.py
│   │   │   │   └── README.md
│   │   │   └── web_search
│   │   │       ├── .env.template
│   │   │       ├── main.py
│   │   │       └── README.md
│   │   └── strands
│   │       └── main.py
│   ├── Makefile
│   ├── pyproject.toml
│   ├── README.md
│   ├── requirements.txt
│   ├── stripe_agent_toolkit
│   │   ├── __init__.py
│   │   ├── api.py
│   │   ├── configuration.py
│   │   ├── crewai
│   │   │   ├── tool.py
│   │   │   └── toolkit.py
│   │   ├── functions.py
│   │   ├── langchain
│   │   │   ├── tool.py
│   │   │   └── toolkit.py
│   │   ├── openai
│   │   │   ├── hooks.py
│   │   │   ├── tool.py
│   │   │   └── toolkit.py
│   │   ├── prompts.py
│   │   ├── schema.py
│   │   ├── strands
│   │   │   ├── __init__.py
│   │   │   ├── hooks.py
│   │   │   ├── tool.py
│   │   │   └── toolkit.py
│   │   └── tools.py
│   └── tests
│       ├── __init__.py
│       ├── test_configuration.py
│       └── test_functions.py
├── README.md
├── SECURITY.md
└── typescript
    ├── .gitignore
    ├── .prettierrc
    ├── eslint.config.mjs
    ├── examples
    │   ├── ai-sdk
    │   │   ├── .env.template
    │   │   ├── index.ts
    │   │   ├── package.json
    │   │   ├── README.md
    │   │   └── tsconfig.json
    │   ├── cloudflare
    │   │   ├── .dev.vars.example
    │   │   ├── .gitignore
    │   │   ├── biome.json
    │   │   ├── package.json
    │   │   ├── README.md
    │   │   ├── src
    │   │   │   ├── app.ts
    │   │   │   ├── imageGenerator.ts
    │   │   │   ├── index.ts
    │   │   │   ├── oauth.ts
    │   │   │   └── utils.ts
    │   │   ├── tsconfig.json
    │   │   ├── worker-configuration.d.ts
    │   │   └── wrangler.jsonc
    │   ├── langchain
    │   │   ├── .env.template
    │   │   ├── index.ts
    │   │   ├── package.json
    │   │   ├── README.md
    │   │   └── tsconfig.json
    │   └── openai
    │       ├── .env.template
    │       ├── index.ts
    │       ├── package.json
    │       ├── README.md
    │       └── tsconfig.json
    ├── jest.config.ts
    ├── package.json
    ├── pnpm-lock.yaml
    ├── pnpm-workspace.yaml
    ├── README.md
    ├── src
    │   ├── ai-sdk
    │   │   ├── index.ts
    │   │   ├── tool.ts
    │   │   └── toolkit.ts
    │   ├── cloudflare
    │   │   ├── index.ts
    │   │   └── README.md
    │   ├── langchain
    │   │   ├── index.ts
    │   │   ├── tool.ts
    │   │   └── toolkit.ts
    │   ├── modelcontextprotocol
    │   │   ├── index.ts
    │   │   ├── README.md
    │   │   ├── register-paid-tool.ts
    │   │   └── toolkit.ts
    │   ├── openai
    │   │   ├── index.ts
    │   │   └── toolkit.ts
    │   ├── shared
    │   │   ├── api.ts
    │   │   ├── balance
    │   │   │   └── retrieveBalance.ts
    │   │   ├── configuration.ts
    │   │   ├── coupons
    │   │   │   ├── createCoupon.ts
    │   │   │   └── listCoupons.ts
    │   │   ├── customers
    │   │   │   ├── createCustomer.ts
    │   │   │   └── listCustomers.ts
    │   │   ├── disputes
    │   │   │   ├── listDisputes.ts
    │   │   │   └── updateDispute.ts
    │   │   ├── documentation
    │   │   │   └── searchDocumentation.ts
    │   │   ├── invoiceItems
    │   │   │   └── createInvoiceItem.ts
    │   │   ├── invoices
    │   │   │   ├── createInvoice.ts
    │   │   │   ├── finalizeInvoice.ts
    │   │   │   └── listInvoices.ts
    │   │   ├── paymentIntents
    │   │   │   └── listPaymentIntents.ts
    │   │   ├── paymentLinks
    │   │   │   └── createPaymentLink.ts
    │   │   ├── prices
    │   │   │   ├── createPrice.ts
    │   │   │   └── listPrices.ts
    │   │   ├── products
    │   │   │   ├── createProduct.ts
    │   │   │   └── listProducts.ts
    │   │   ├── refunds
    │   │   │   └── createRefund.ts
    │   │   ├── subscriptions
    │   │   │   ├── cancelSubscription.ts
    │   │   │   ├── listSubscriptions.ts
    │   │   │   └── updateSubscription.ts
    │   │   └── tools.ts
    │   └── test
    │       ├── modelcontextprotocol
    │       │   └── register-paid-tool.test.ts
    │       └── shared
    │           ├── balance
    │           │   ├── functions.test.ts
    │           │   └── parameters.test.ts
    │           ├── configuration.test.ts
    │           ├── customers
    │           │   ├── functions.test.ts
    │           │   └── parameters.test.ts
    │           ├── disputes
    │           │   └── functions.test.ts
    │           ├── documentation
    │           │   ├── functions.test.ts
    │           │   └── parameters.test.ts
    │           ├── invoiceItems
    │           │   ├── functions.test.ts
    │           │   ├── parameters.test.ts
    │           │   └── prompts.test.ts
    │           ├── invoices
    │           │   ├── functions.test.ts
    │           │   ├── parameters.test.ts
    │           │   └── prompts.test.ts
    │           ├── paymentIntents
    │           │   ├── functions.test.ts
    │           │   ├── parameters.test.ts
    │           │   └── prompts.test.ts
    │           ├── paymentLinks
    │           │   ├── functions.test.ts
    │           │   ├── parameters.test.ts
    │           │   └── prompts.test.ts
    │           ├── prices
    │           │   ├── functions.test.ts
    │           │   └── parameters.test.ts
    │           ├── products
    │           │   ├── functions.test.ts
    │           │   └── parameters.test.ts
    │           ├── refunds
    │           │   ├── functions.test.ts
    │           │   └── parameters.test.ts
    │           └── subscriptions
    │               ├── functions.test.ts
    │               ├── parameters.test.ts
    │               └── prompts.test.ts
    ├── tsconfig.json
    └── tsup.config.ts
```

# Files

--------------------------------------------------------------------------------
/modelcontextprotocol/.node-version:
--------------------------------------------------------------------------------

```
1 | 22.14.0
2 | 
```

--------------------------------------------------------------------------------
/evals/.gitignore:
--------------------------------------------------------------------------------

```
1 | node_modules
2 | .env
3 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/.gitignore:
--------------------------------------------------------------------------------

```
1 | dist/
2 | node_modules/
3 | *.dxt
4 | dxt-dist/
```

--------------------------------------------------------------------------------
/python/examples/openai/.env.template:
--------------------------------------------------------------------------------

```
1 | OPENAI_API_KEY=""
2 | STRIPE_SECRET_KEY=""
```

--------------------------------------------------------------------------------
/typescript/examples/openai/.env.template:
--------------------------------------------------------------------------------

```
1 | OPENAI_API_KEY=""
2 | STRIPE_SECRET_KEY=""
```

--------------------------------------------------------------------------------
/typescript/examples/cloudflare/.gitignore:
--------------------------------------------------------------------------------

```
1 | # wrangler project
2 | .dev.vars
3 | .wrangler/
4 | 
```

--------------------------------------------------------------------------------
/typescript/examples/langchain/.env.template:
--------------------------------------------------------------------------------

```
1 | LANGSMITH_API_KEY=""
2 | STRIPE_SECRET_KEY=""
3 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/.dxtignore:
--------------------------------------------------------------------------------

```
1 | node_modules/
2 | node_modules/**/*.*
3 | tsconfig.json
4 | Dockerfile
```

--------------------------------------------------------------------------------
/python/examples/openai/web_search/.env.template:
--------------------------------------------------------------------------------

```
1 | OPENAI_API_KEY=""
2 | STRIPE_SECRET_KEY=""
3 | STRIPE_CUSTOMER_ID=""
4 | STRIPE_METER=""
5 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/.prettierrc:
--------------------------------------------------------------------------------

```
1 | {
2 |   "singleQuote": true,
3 |   "trailingComma": "es5",
4 |   "bracketSpacing": false
5 | }
6 | 
```

--------------------------------------------------------------------------------
/typescript/.prettierrc:
--------------------------------------------------------------------------------

```
1 | {
2 |   "singleQuote": true,
3 |   "trailingComma": "es5",
4 |   "bracketSpacing": false
5 | }
6 | 
```

--------------------------------------------------------------------------------
/python/examples/crewai/.env.template:
--------------------------------------------------------------------------------

```
1 | STRIPE_SECRET_KEY=""
2 | OPENAI_API_BASE=""
3 | OPENAI_MODEL_NAME="gpt-4o"
4 | OPENAI_API_KEY=""
5 | 
```

--------------------------------------------------------------------------------
/typescript/examples/ai-sdk/.env.template:
--------------------------------------------------------------------------------

```
1 | STRIPE_SECRET_KEY=""
2 | STRIPE_CUSTOMER_ID=""
3 | STRIPE_METER_INPUT=""
4 | STRIPE_METER_OUTPUT=""
5 | 
```

--------------------------------------------------------------------------------
/python/examples/langchain/.env.template:
--------------------------------------------------------------------------------

```
1 | LANGSMITH_API_KEY=""
2 | STRIPE_SECRET_KEY=""
3 | OPENAI_API_BASE=""
4 | OPENAI_MODEL_NAME="gpt-4o"
5 | OPENAI_API_KEY=""
6 | 
```

--------------------------------------------------------------------------------
/evals/.env.example:
--------------------------------------------------------------------------------

```
 1 | BRAINTRUST_API_KEY=...
 2 | STRIPE_SECRET_KEY=...
 3 | 
 4 | # Enable if your OpenAI API is behind a unix socket proxy:
 5 | # SOCKET_PROXY_PATH=""
 6 | OPENAI_BASE_URL=http://0.0.0.0:8000/v1
 7 | OPENAI_API_KEY=EMPTY
 8 | 
 9 | 
10 | 
11 | 
```

--------------------------------------------------------------------------------
/typescript/examples/cloudflare/.dev.vars.example:
--------------------------------------------------------------------------------

```
1 | STRIPE_SECRET_KEY=sk_test_......
2 | STRIPE_PRICE_ID_ONE_TIME_PAYMENT=price_1RJJwjR1b4cWtS0UCIDTSU3V
3 | STRIPE_PRICE_ID_SUBSCRIPTION=price_1RJJwjR1bGyW9S0UCIDTSU3V
4 | STRIPE_PRICE_ID_USAGE_BASED_SUBSCRIPTION=price_1RJdGWR1bGyW9S0UucbYBFBZ
```

--------------------------------------------------------------------------------
/python/.editorconfig:
--------------------------------------------------------------------------------

```
 1 | ; https://editorconfig.org/
 2 | 
 3 | root = true
 4 | 
 5 | [*]
 6 | indent_style = space
 7 | indent_size = 4
 8 | insert_final_newline = true
 9 | trim_trailing_whitespace = true
10 | end_of_line = lf
11 | charset = utf-8
12 | 
13 | [*.{cfg,ini,json,toml,yml}]
14 | indent_size = 2
15 | 
16 | [Makefile]
17 | indent_style = tab
18 | 
```

--------------------------------------------------------------------------------
/python/examples/openai/customer_support/.env.template:
--------------------------------------------------------------------------------

```
 1 | OPENAI_API_KEY=your_openai_api_key
 2 | STRIPE_SECRET_KEY=your_stripe_secret_key
 3 | 
 4 | # Your email address and app password
 5 | # https://support.google.com/accounts/answer/185833?hl=en
 6 | [email protected]
 7 | EMAIL_PASSWORD=your_app_specific_password
 8 | # Only respond to emails send to this address (defaults to $EMAIL_ADDRESS)
 9 | SUPPORT_ADDRESS="[email protected]"
10 | 
11 | # If your connecting to gmail, you don't need to customize these
12 | IMAP_SERVER=imap.gmail.com
13 | IMAP_PORT=993
14 | SMTP_SERVER=smtp.gmail.com
15 | SMTP_PORT=587
16 | 
```

--------------------------------------------------------------------------------
/python/.flake8:
--------------------------------------------------------------------------------

```
 1 | [flake8]
 2 | # E501 is the "Line too long" error. We disable it because we use Black for
 3 | # code formatting. Black makes a best effort to keep lines under the max
 4 | # length, but can go over in some cases.
 5 | # W503 goes against PEP8 rules. It's disabled by default, but must be disabled
 6 | # explicitly when using `ignore`.
 7 | # E704 is disabled in the default configuration, but by specifying `ignore`, we wipe that out.
 8 | # ruff formatting creates code that violates it, so we have to disable it manually
 9 | ignore = E501, W503, E704
10 | per-file-ignores =
11 |     # setup.py is required for tooling
12 |     setup.py: IMP102
13 | 
```

--------------------------------------------------------------------------------
/typescript/.gitignore:
--------------------------------------------------------------------------------

```
  1 | # Logs
  2 | logs
  3 | *.log
  4 | npm-debug.log*
  5 | yarn-debug.log*
  6 | yarn-error.log*
  7 | lerna-debug.log*
  8 | .pnpm-debug.log*
  9 | 
 10 | # Diagnostic reports (https://nodejs.org/api/report.html)
 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
 12 | 
 13 | # Runtime data
 14 | pids
 15 | *.pid
 16 | *.seed
 17 | *.pid.lock
 18 | 
 19 | # Directory for instrumented libs generated by jscoverage/JSCover
 20 | lib-cov
 21 | 
 22 | # Coverage directory used by tools like istanbul
 23 | coverage
 24 | *.lcov
 25 | 
 26 | # nyc test coverage
 27 | .nyc_output
 28 | 
 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
 30 | .grunt
 31 | 
 32 | # Bower dependency directory (https://bower.io/)
 33 | bower_components
 34 | 
 35 | # node-waf configuration
 36 | .lock-wscript
 37 | 
 38 | # Compiled binary addons (https://nodejs.org/api/addons.html)
 39 | build/Release
 40 | 
 41 | # Dependency directories
 42 | node_modules/
 43 | jspm_packages/
 44 | junk/
 45 | 
 46 | # Snowpack dependency directory (https://snowpack.dev/)
 47 | web_modules/
 48 | 
 49 | # TypeScript cache
 50 | *.tsbuildinfo
 51 | 
 52 | # Optional npm cache directory
 53 | .npm
 54 | 
 55 | # Optional eslint cache
 56 | .eslintcache
 57 | 
 58 | # Optional stylelint cache
 59 | .stylelintcache
 60 | 
 61 | # Microbundle cache
 62 | .rpt2_cache/
 63 | .rts2_cache_cjs/
 64 | .rts2_cache_es/
 65 | .rts2_cache_umd/
 66 | 
 67 | # Optional REPL history
 68 | .node_repl_history
 69 | 
 70 | # Output of 'npm pack'
 71 | *.tgz
 72 | 
 73 | # Yarn Integrity file
 74 | .yarn-integrity
 75 | 
 76 | # dotenv environment variable files
 77 | .env
 78 | .env.development.local
 79 | .env.test.local
 80 | .env.production.local
 81 | .env.local
 82 | 
 83 | # parcel-bundler cache (https://parceljs.org/)
 84 | .cache
 85 | .parcel-cache
 86 | 
 87 | # Next.js build output
 88 | .next
 89 | out
 90 | 
 91 | # Nuxt.js build / generate output
 92 | .nuxt
 93 | dist
 94 | 
 95 | # Gatsby files
 96 | .cache/
 97 | # Comment in the public line in if your project uses Gatsby and not Next.js
 98 | # https://nextjs.org/blog/next-9-1#public-directory-support
 99 | # public
100 | 
101 | # vuepress build output
102 | .vuepress/dist
103 | 
104 | # vuepress v2.x temp and cache directory
105 | .temp
106 | .cache
107 | 
108 | # Docusaurus cache and generated files
109 | .docusaurus
110 | 
111 | # Serverless directories
112 | .serverless/
113 | 
114 | # FuseBox cache
115 | .fusebox/
116 | 
117 | # DynamoDB Local files
118 | .dynamodb/
119 | 
120 | # TernJS port file
121 | .tern-port
122 | 
123 | # Stores VSCode versions used for testing VSCode extensions
124 | .vscode-test
125 | 
126 | # yarn v2
127 | .yarn/cache
128 | .yarn/unplugged
129 | .yarn/build-state.yml
130 | .yarn/install-state.gz
131 | .pnp.*
132 | 
133 | .turbo
134 | 
135 | 
136 | /cloudflare/
137 | /openai/
138 | /ai-sdk/
139 | /langchain/
140 | /modelcontextprotocol/
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
  1 | # Byte-compiled / optimized / DLL files
  2 | __pycache__/
  3 | *.py[cod]
  4 | *$py.class
  5 | 
  6 | # C extensions
  7 | *.so
  8 | 
  9 | # Node modules
 10 | node_modules/
 11 | junk/
 12 | 
 13 | # Distribution / packaging
 14 | .Python
 15 | build/
 16 | develop-eggs/
 17 | dist/
 18 | downloads/
 19 | eggs/
 20 | .eggs/
 21 | lib/
 22 | lib64/
 23 | parts/
 24 | sdist/
 25 | var/
 26 | wheels/
 27 | share/python-wheels/
 28 | *.egg-info/
 29 | .installed.cfg
 30 | *.egg
 31 | MANIFEST
 32 | 
 33 | # PyInstaller
 34 | #  Usually these files are written by a python script from a template
 35 | #  before PyInstaller builds the exe, so as to inject date/other infos into it.
 36 | *.manifest
 37 | *.spec
 38 | 
 39 | # Installer logs
 40 | pip-log.txt
 41 | pip-delete-this-directory.txt
 42 | 
 43 | # Unit test / coverage reports
 44 | htmlcov/
 45 | .tox/
 46 | .nox/
 47 | .coverage
 48 | .coverage.*
 49 | .cache
 50 | nosetests.xml
 51 | coverage.xml
 52 | *.cover
 53 | *.py,cover
 54 | .hypothesis/
 55 | .pytest_cache/
 56 | cover/
 57 | 
 58 | # Translations
 59 | *.mo
 60 | *.pot
 61 | 
 62 | # Django stuff:
 63 | *.log
 64 | local_settings.py
 65 | db.sqlite3
 66 | db.sqlite3-journal
 67 | 
 68 | # Flask stuff:
 69 | instance/
 70 | .webassets-cache
 71 | 
 72 | # Scrapy stuff:
 73 | .scrapy
 74 | 
 75 | # Sphinx documentation
 76 | docs/_build/
 77 | 
 78 | # PyBuilder
 79 | .pybuilder/
 80 | target/
 81 | 
 82 | # Jupyter Notebook
 83 | .ipynb_checkpoints
 84 | 
 85 | # IPython
 86 | profile_default/
 87 | ipython_config.py
 88 | 
 89 | # pyenv
 90 | #   For a library or package, you might want to ignore these files since the code is
 91 | #   intended to run in multiple environments; otherwise, check them in:
 92 | # .python-version
 93 | 
 94 | # pipenv
 95 | #   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
 96 | #   However, in case of collaboration, if having platform-specific dependencies or dependencies
 97 | #   having no cross-platform support, pipenv may install dependencies that don't work, or not
 98 | #   install all needed dependencies.
 99 | #Pipfile.lock
100 | 
101 | # poetry
102 | #   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
103 | #   This is especially recommended for binary packages to ensure reproducibility, and is more
104 | #   commonly ignored for libraries.
105 | #   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
106 | #poetry.lock
107 | 
108 | # pdm
109 | #   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
110 | #pdm.lock
111 | #   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
112 | #   in version control.
113 | #   https://pdm.fming.dev/#use-with-ide
114 | .pdm.toml
115 | 
116 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
117 | __pypackages__/
118 | 
119 | # Celery stuff
120 | celerybeat-schedule
121 | celerybeat.pid
122 | 
123 | # SageMath parsed files
124 | *.sage.py
125 | 
126 | # Environments
127 | .env
128 | .venv
129 | env/
130 | venv/
131 | ENV/
132 | env.bak/
133 | venv.bak/
134 | 
135 | # Spyder project settings
136 | .spyderproject
137 | .spyproject
138 | 
139 | # Rope project settings
140 | .ropeproject
141 | 
142 | # mkdocs documentation
143 | /site
144 | 
145 | # mypy
146 | .mypy_cache/
147 | .dmypy.json
148 | dmypy.json
149 | 
150 | # Pyre type checker
151 | .pyre/
152 | 
153 | # pytype static type analyzer
154 | .pytype/
155 | 
156 | # Cython debug symbols
157 | cython_debug/
158 | 
159 | # PyCharm
160 | #  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
161 | #  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
162 | #  and can be added to the global gitignore or merged into this file.  For a more nuclear
163 | #  option (not recommended) you can uncomment the following to ignore the entire idea folder.
164 | #.idea/
165 | 
```

--------------------------------------------------------------------------------
/python/examples/crewai/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # CrewAI Example
 2 | 
 3 | ## Setup
 4 | 
 5 | Copy the `.env.template` and populate with your values.
 6 | 
 7 | ```
 8 | cp .env.template .env
 9 | ```
10 | 
11 | ## Usage
12 | 
13 | ```
14 | python main.py
15 | ```
16 | 
```

--------------------------------------------------------------------------------
/python/examples/langchain/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # LangChain Example
 2 | 
 3 | ## Setup
 4 | 
 5 | Copy the `.env.template` and populate with your values.
 6 | 
 7 | ```
 8 | cp .env.template .env
 9 | ```
10 | 
11 | ## Usage
12 | 
13 | ```
14 | python main.py
15 | ```
16 | 
```

--------------------------------------------------------------------------------
/typescript/examples/ai-sdk/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # AI SDK Example
 2 | 
 3 | ## Setup
 4 | 
 5 | Copy the `.env.template` and populate with your values.
 6 | 
 7 | ```
 8 | cp .env.template .env
 9 | ```
10 | 
11 | ## Usage
12 | 
13 | ```
14 | npx ts-node index.ts --env
15 | ```
16 | 
```

--------------------------------------------------------------------------------
/typescript/examples/openai/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # OpenAI Example
 2 | 
 3 | ## Setup
 4 | 
 5 | Copy the `.env.template` and populate with your values.
 6 | 
 7 | ```
 8 | cp .env.template .env
 9 | ```
10 | 
11 | ## Usage
12 | 
13 | ```
14 | npx ts-node index.ts --env
15 | ```
16 | 
```

--------------------------------------------------------------------------------
/typescript/examples/langchain/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # LangChain Example
 2 | 
 3 | ## Setup
 4 | 
 5 | Copy the `.env.template` and populate with your values.
 6 | 
 7 | ```
 8 | cp .env.template .env
 9 | ```
10 | 
11 | ## Usage
12 | 
13 | ```
14 | npx ts-node index.ts --env
15 | ```
16 | 
```

--------------------------------------------------------------------------------
/python/examples/openai/file_search/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Web Search Example
 2 | 
 3 | This example shows how to use the Stripe Agent Toolkit with OpenAI to create an agent that can search the web and charge for outcomes.
 4 | 
 5 | ## Setup
 6 | 
 7 | 1. Create a OpenAI Vector Store following the [OpenAI documentation](https://platform.openai.com/docs/api-reference/vector-stores-files) and add the files you want to search.
 8 | 
 9 | 2. Copy `.env.template` to `.env` populate with the relevant values.
10 | 
11 | ```bash
12 | OPENAI_API_KEY=your_openai_api_key
13 | OPENAI_VECTOR_STORE_ID=your_openai_vector_store_id
14 | STRIPE_SECRET_KEY=your_stripe_secret_key
15 | ```
16 | 
17 | ## Usage
18 | 
19 | ```bash
20 | python main.py
21 | ```
22 | 
23 | You can see the invoices created in the Stripe Dashboard.
24 | 
```

--------------------------------------------------------------------------------
/python/examples/openai/web_search/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Web Search Example
 2 | 
 3 | This example shows how to use the Stripe Agent Toolkit with OpenAI to create an agent that can search the web and charge for outcomes.
 4 | 
 5 | ## Setup
 6 | 
 7 | 1. Create a Stripe Billing Meter and Stripe Customer following the [Stripe documentation](https://docs.stripe.com/billing/subscriptions/usage-based/implementation-guide).
 8 | 
 9 | 2. Copy `.env.template` to `.env` populate with the relevant values.
10 | 
11 | ```bash
12 | OPENAI_API_KEY=your_openai_api_key
13 | STRIPE_SECRET_KEY=your_stripe_secret_key
14 | STRIPE_CUSTOMER_ID=your_stripe_customer_id
15 | STRIPE_METER=your_stripe_meter
16 | ```
17 | 
18 | ## Usage
19 | 
20 | ```bash
21 | python main.py
22 | ```
23 | 
24 | You can see the usage in the Stripe Dashboard.
25 | 
```

--------------------------------------------------------------------------------
/typescript/src/modelcontextprotocol/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # MCP Payments
 2 | 
 3 | A simple MCP server helper to require payment to use tools, whether subscription or usage-based.
 4 | 
 5 | This implementation works on Vercel with a standard MCP server.
 6 | 
 7 | ## Usage Instructions for `registerPaidTool`
 8 | 
 9 | 1. Import the `registerPaidTool` function from this package.
10 | 2. Call `registerPaidTool` with your MCP server, tool name, description, params schema, callback, and payment options.
11 | 3. Example usage:
12 | 
13 | ```ts
14 | import {registerPaidTool} from './register-paid-tool';
15 | import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';
16 | 
17 | const server = new McpServer({
18 |   name: 'mcp-typescript server',
19 |   version: '0.1.0',
20 | });
21 | 
22 | registerPaidTool(
23 |   server,
24 |   'add_numbers',
25 |   {
26 |     a: z.number(),
27 |     b: z.number(),
28 |   },
29 |   ({a, b}) => {
30 |     return {
31 |       content: [{type: 'text', text: `Result: ${a + b}`}],
32 |     };
33 |   },
34 |   {
35 |     priceId: '{{PRICE_ID}}',
36 |     successUrl: '{{CALLBACK_URL}}',
37 |     email: '{{EMAIL}}',
38 |     paymentReason:
39 |       'You must pay a subscription to add two big numbers together.',
40 |     stripeSecretKey: '{{SECRET_KEY}}',
41 |   }
42 | );
43 | ```
44 | 
```

--------------------------------------------------------------------------------
/typescript/examples/cloudflare/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # PaidMcpAgent
 2 | 
 3 | An example of how to monetize an MCP server with Stripe.
 4 | 
 5 | ## Setup
 6 | 
 7 | 1. Copy `.dev.vars.example` to `.dev.vars` and add your Stripe API key.
 8 | 2. Configure the required Stripe environment variables:
 9 |    - `STRIPE_SECRET_KEY`: Your Stripe secret key
10 |    - `STRIPE_ONETIME_SUBSCRIPTION_PRICE_ID`: Price ID for one-time payment
11 |    - `STRIPE_PRICE_ID_USAGE_BASED_SUBSCRIPTION`: Price ID for usage-based subscription
12 |    - `STRIPE_METER_EVENT_NAME`: Event name for usage metering
13 | 3. This demo uses an example fake OAuth implementation for the MCP server. We recommend following the [authorization](https://developers.cloudflare.com/agents/model-context-protocol/authorization/) Cloudflare docs.
14 | 
15 | ## Development
16 | 
17 | ```
18 | pnpm i
19 | pnpm dev
20 | ```
21 | 
22 | ## Testing
23 | 
24 | Open up the inspector and connect to your MCP server.
25 | 
26 | ```
27 | npx @modelcontextprotocol/inspector@latest http://localhost:4242/sse
28 | ```
29 | 
30 | ### Deploy
31 | 
32 | ```
33 | npx wrangler secret put STRIPE_SECRET_KEY
34 | npx wrangler secret put STRIPE_PRICE_ID_ONE_TIME_PAYMENT
35 | npx wrangler secret put STRIPE_ONETIME_SUBSCRIPTION_PRICE_ID
36 | npx wrangler secret put STRIPE_PRICE_ID_USAGE_BASED_SUBSCRIPTION
37 | ```
38 | 
39 | ### Feedback
40 | 
41 | Please leave feedback throught the GitHub issues and discussions on how you
42 | would use the `PaidMcpAgent`!
43 | 
```

--------------------------------------------------------------------------------
/evals/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | ## Evals
 2 | 
 3 | Set up `.env` file with the following (see `.env.example` for an example):
 4 | 
 5 | ```
 6 | BRAINTRUST_API_KEY=...
 7 | STRIPE_SECRET_KEY=sk_test_....
 8 | OPENAI_BASE_URL=http://0.0.0.0:8000/v1
 9 | OPENAI_API_KEY=EMPTY
10 | ```
11 | 
12 | To run:
13 | 
14 | ```
15 | tsx eval.ts
16 | ```
17 | 
18 | We are using [Braintrust](https://www.braintrust.dev/) to run the evals.
19 | 
20 | ## Framework
21 | 
22 | There is a very lightweight built-in testing framework that wraps Braintrust to make adding new test cases easy.
23 | 
24 | Add a new test case to `cases.ts`:
25 | 
26 | ```javascript
27 | test({
28 |   prompt:
29 |     "Create a product called 'Test Product' with a description 'A test product for evaluation'",
30 |   fn: ({ toolCalls, messages }) => [
31 |     expectToolCall(toolCalls, ["create_product"]),
32 |     llmCriteriaMet(
33 |       messages,
34 |       "The message should include a successful production creation response"
35 |     ),
36 |   ],
37 | });
38 | ```
39 | 
40 | The Typescript type defintions has documentation to help you. The `fn` function
41 | will be called with the resulting output of your prompt. This should return an array of "assertions." These are like `expect` in Jest.
42 | 
43 | This can be as simple as noting a tool was called or as complex as asking an LLM to do semantic similarities. See `scorer.ts` for a list of assertions.
44 | 
45 | Override the toolkit config by passing a `toolkitConfig` object.
46 | 
47 | If your test case needs some set up, for example, if it needs to set up some state in the Stripe account or load data, you can pass an async function.
48 | 
49 | ```javascript
50 | test(async () => {
51 |   const customers = await stripe.customers.list();
52 | 
53 |   return {
54 |     prompt: "What are my payments",
55 |     toolkitConfig: {
56 |       context: {
57 |         customer: customers.data[0].id,
58 |       },
59 |     },
60 |     fn: ({ toolCalls, messages }) => [],
61 |   };
62 | });
63 | ```
64 | 
```

--------------------------------------------------------------------------------
/python/examples/openai/customer_support/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Email Support Agent
 2 | 
 3 | Sample app to help you automate your email support. Powered by OpenAI's Agent SDK and [Stripe Agent Toolkit](https://github.com/stripe/agent-toolkit).
 4 | 
 5 | Customize this agent to fit your own needs by cloning and modifying [support_agent.py](./support_agent.py).
 6 | 
 7 | ## Features
 8 | 
 9 | The support agent currently can:
10 | 
11 | - Answer FAQ questions
12 | - Update billing information through Customer Portal
13 | - Send any missing invoices
14 | 
15 | We also support a REPL to help you test your agent without sending a gazillion emails.
16 | 
17 | ## How it Works
18 | 
19 | The support agent will:
20 | 
21 | - Connects to your email using an IMAP client
22 | - Checks for unread emails every 30 seconds
23 | - Generates and sends a reply
24 | - Marks the emails as read
25 | 
26 | If it doesn't know how to answer the question, it will not respond and ignore the email.
27 | 
28 | ## Setup
29 | 
30 | 1. Install uv (if not already installed):
31 | 
32 | ```bash
33 | curl -LsSf https://astral.sh/uv/install.sh | sh
34 | ```
35 | 
36 | 2. Clone this repository
37 | 3. Create and activate a virtual environment:
38 | 
39 | ```bash
40 | uv venv
41 | source .venv/bin/activate  # On Unix/macOS
42 | # or
43 | .venv\Scripts\activate  # On Windows
44 | ```
45 | 
46 | 4. Install dependencies:
47 | 
48 | ```bash
49 | uv sync
50 | ```
51 | 
52 | 5. Copy `.env.example` to `.env`:
53 | 
54 | ```bash
55 | cp .env.example .env
56 | ```
57 | 
58 | 6. Configure your `.env` file with:
59 |    - Email credentials (create an [app-specific password](https://support.google.com/accounts/answer/185833) for Gmail)
60 |    - IMAP/SMTP server details (defaults for Gmail provided in .env.example)
61 |    - OpenAI API key
62 |    - Stripe Secret Key
63 | 
64 | ## Usage
65 | 
66 | Run the agent:
67 | 
68 | ```bash
69 | python main.py
70 | ```
71 | 
72 | Run the REPL with:
73 | 
74 | ```bash
75 | python repl.py
76 | ```
77 | 
78 | ## Customize for your App
79 | 
80 | This repository is just a sample app tailored to our [example website](http://standupjack.com).
81 | 
82 | We recommend cloning this repository and customizing the system prompt and tools in [support_agent.py](./support_agent.py). It's very easy to add new capabilities.
83 | 
```

--------------------------------------------------------------------------------
/typescript/src/cloudflare/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # MCP Payments
 2 | 
 3 | `PaidMcpAgent` extends [Cloudflare's `McpAgent`](https://github.com/cloudflare/agents) to make it simple to require payment to use tools, whether subscription or usage-based. For a full end-to-end example, see [/examples/cloudflare](../../examples/cloudflare/).
 4 | 
 5 | ## Usage
 6 | 
 7 | ### Setup
 8 | 
 9 | ```
10 | npm install @stripe/agent-toolkit
11 | ```
12 | 
13 | Modify your existing MCP server by extending with `PaidMcpAgent` instead of `McpAgent`.
14 | 
15 | ```ts
16 | import {
17 |   PaymentState,
18 |   experimental_PaidMcpAgent as PaidMcpAgent,
19 | } from '@stripe/agent-toolkit/cloudflare';
20 | 
21 | type Props = {
22 |   userEmail: string;
23 | };
24 | 
25 | type State = PaymentState & {};
26 | 
27 | export class MyMCP extends PaidMcpAgent<Bindings, State, Props> {}
28 | ```
29 | 
30 | Lastly, set your `STRIPE_SECRET_KEY` in `.dev.vars` to test, and then `npx wrangler secret put STRIPE_SECRET_KEY` when ready for production.
31 | 
32 | ### Monetizing a tool
33 | 
34 | Consider a basic tool that can add two numbers together:
35 | 
36 | ```ts
37 | this.server.tool('add', {a: z.number(), b: z.number()}, ({a, b}) => {
38 |   return {
39 |     content: [{type: 'text', text: `Result: ${a + b}`}],
40 |   };
41 | });
42 | ```
43 | 
44 | To make this paid using a subscription, first create a product and price in the Stripe Dashboard.
45 | 
46 | Then, replace `this.server.tool` with `this.paidTool` and add your payment config: `priceId`, `paymentReason`, and `successUrl`.
47 | 
48 | ```ts
49 | this.paidTool(
50 |   'add_numbers',
51 |   {
52 |     a: z.number(),
53 |     b: z.number(),
54 |   },
55 |   ({a, b}) => {
56 |     return {
57 |       content: [{type: 'text', text: `Result: ${a + b}`}],
58 |     };
59 |   },
60 |   {
61 |     priceId: '{{PRICE_ID}}',
62 |     successUrl: 'https://mcp.mysite.com/success',
63 |     paymentReason:
64 |       'You must pay a subscription to add two big numbers together.',
65 |   }
66 | );
67 | ```
68 | 
69 | ## Authentication
70 | 
71 | `PaidMcp` relies on `props.userEmail` to identify (or create) a Stripe customer. You can prepopulate this directly, or integrate with `OAuthProvider` from `@cloudflare/workers-oauth-provider` to set the prop on succesful authentication.
72 | 
```

--------------------------------------------------------------------------------
/python/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Stripe Agent Toolkit - Python
 2 | 
 3 | The Stripe Agent Toolkit library enables popular agent frameworks including OpenAI's Agent SDK, LangChain, and CrewAI to integrate with Stripe APIs through function calling. The
 4 | library is not exhaustive of the entire Stripe API. It is built directly on top
 5 | of the [Stripe Python SDK][python-sdk].
 6 | 
 7 | ## Installation
 8 | 
 9 | You don't need this source code unless you want to modify the package. If you just
10 | want to use the package, just run:
11 | 
12 | ```sh
13 | pip install stripe-agent-toolkit
14 | ```
15 | 
16 | ### Requirements
17 | 
18 | -   Python 3.11+
19 | 
20 | ## Usage
21 | 
22 | The library needs to be configured with your account's secret key which is
23 | available in your [Stripe Dashboard][api-keys].
24 | 
25 | ```python
26 | from stripe_agent_toolkit.openai.toolkit import StripeAgentToolkit
27 | 
28 | stripe_agent_toolkit = StripeAgentToolkit(
29 |     secret_key="sk_test_...",
30 |     configuration={
31 |         "actions": {
32 |             "payment_links": {
33 |                 "create": True,
34 |             },
35 |         }
36 |     },
37 | )
38 | ```
39 | 
40 | The toolkit works with OpenAI's Agent SDK, LangChain, and CrewAI and can be passed as a list of tools. For example:
41 | 
42 | ```python
43 | from agents import Agent
44 | 
45 | stripe_agent = Agent(
46 |     name="Stripe Agent",
47 |     instructions="You are an expert at integrating with Stripe",
48 |     tools=stripe_agent_toolkit.get_tools()
49 | )
50 | ```
51 | 
52 | Examples for OpenAI's Agent SDK,LangChain, and CrewAI are included in [/examples](/examples).
53 | 
54 | [python-sdk]: https://github.com/stripe/stripe-python
55 | [api-keys]: https://dashboard.stripe.com/account/apikeys
56 | 
57 | #### Context
58 | 
59 | In some cases you will want to provide values that serve as defaults when making requests. Currently, the `account` context value enables you to make API calls for your [connected accounts](https://docs.stripe.com/connect/authentication).
60 | 
61 | ```python
62 | stripe_agent_toolkit = StripeAgentToolkit(
63 |     secret_key="sk_test_...",
64 |     configuration={
65 |         "context": {
66 |             "account": "acct_123"
67 |         }
68 |     }
69 | )
70 | ```
71 | 
72 | ## Development
73 | 
74 | ```
75 | python3 -m venv venv
76 | source venv/bin/activate
77 | pip install -r requirements.txt
78 | ```
79 | 
```

--------------------------------------------------------------------------------
/typescript/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Stripe Agent Toolkit - TypeScript
  2 | 
  3 | The Stripe Agent Toolkit enables popular agent frameworks including LangChain and Vercel's AI SDK to integrate with Stripe APIs through function calling. It also provides tooling to quickly integrate metered billing for prompt and completion token usage.
  4 | 
  5 | ## Installation
  6 | 
  7 | You don't need this source code unless you want to modify the package. If you just
  8 | want to use the package run:
  9 | 
 10 | ```
 11 | npm install @stripe/agent-toolkit
 12 | ```
 13 | 
 14 | ### Requirements
 15 | 
 16 | - Node 18+
 17 | 
 18 | ## Usage
 19 | 
 20 | The library needs to be configured with your account's secret key which is available in your [Stripe Dashboard][api-keys]. Additionally, `configuration` enables you to specify the types of actions that can be taken using the toolkit.
 21 | 
 22 | ```typescript
 23 | import {StripeAgentToolkit} from '@stripe/agent-toolkit/langchain';
 24 | 
 25 | const stripeAgentToolkit = new StripeAgentToolkit({
 26 |   secretKey: process.env.STRIPE_SECRET_KEY!,
 27 |   configuration: {
 28 |     actions: {
 29 |       paymentLinks: {
 30 |         create: true,
 31 |       },
 32 |     },
 33 |   },
 34 | });
 35 | ```
 36 | 
 37 | ### Tools
 38 | 
 39 | The toolkit works with LangChain and Vercel's AI SDK and can be passed as a list of tools. For example:
 40 | 
 41 | ```typescript
 42 | import {AgentExecutor, createStructuredChatAgent} from 'langchain/agents';
 43 | 
 44 | const tools = stripeAgentToolkit.getTools();
 45 | 
 46 | const agent = await createStructuredChatAgent({
 47 |   llm,
 48 |   tools,
 49 |   prompt,
 50 | });
 51 | 
 52 | const agentExecutor = new AgentExecutor({
 53 |   agent,
 54 |   tools,
 55 | });
 56 | ```
 57 | 
 58 | #### Context
 59 | 
 60 | In some cases you will want to provide values that serve as defaults when making requests. Currently, the `account` context value enables you to make API calls for your [connected accounts](https://docs.stripe.com/connect/authentication).
 61 | 
 62 | ```typescript
 63 | const stripeAgentToolkit = new StripeAgentToolkit({
 64 |   secretKey: process.env.STRIPE_SECRET_KEY!,
 65 |   configuration: {
 66 |     context: {
 67 |       account: 'acct_123',
 68 |     },
 69 |   },
 70 | });
 71 | ```
 72 | 
 73 | ### Metered billing
 74 | 
 75 | For Vercel's AI SDK, you can use middleware to submit billing events for usage. All that is required is the customer ID and the input/output meters to bill.
 76 | 
 77 | ```typescript
 78 | import {StripeAgentToolkit} from '@stripe/agent-toolkit/ai-sdk';
 79 | import {openai} from '@ai-sdk/openai';
 80 | import {
 81 |   generateText,
 82 |   experimental_wrapLanguageModel as wrapLanguageModel,
 83 | } from 'ai';
 84 | 
 85 | const stripeAgentToolkit = new StripeAgentToolkit({
 86 |   secretKey: process.env.STRIPE_SECRET_KEY!,
 87 |   configuration: {
 88 |     actions: {
 89 |       paymentLinks: {
 90 |         create: true,
 91 |       },
 92 |     },
 93 |   },
 94 | });
 95 | 
 96 | const model = wrapLanguageModel({
 97 |   model: openai('gpt-4o'),
 98 |   middleware: stripeAgentToolkit.middleware({
 99 |     billing: {
100 |       customer: 'cus_123',
101 |       meters: {
102 |         input: 'input_tokens',
103 |         output: 'output_tokens',
104 |       },
105 |     },
106 |   }),
107 | });
108 | ```
109 | 
110 | This works with both `generateText` and `generateStream` from the Vercel AI SDK.
111 | 
112 | ## Model Context Protocol
113 | 
114 | The Stripe Agent Toolkit also supports the [Model Context Protocol (MCP)](https://modelcontextprotocol.com/). See `/examples/modelcontextprotocol` for an example. The same configuration options are available, and the server can be run with all supported transports.
115 | 
116 | ```typescript
117 | import {StripeAgentToolkit} from '@stripe/agent-toolkit/modelcontextprotocol';
118 | import {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js';
119 | 
120 | const server = new StripeAgentToolkit({
121 |   secretKey: process.env.STRIPE_SECRET_KEY!,
122 |   configuration: {
123 |     actions: {
124 |       paymentLinks: {
125 |         create: true,
126 |       },
127 |       products: {
128 |         create: true,
129 |       },
130 |       prices: {
131 |         create: true,
132 |       },
133 |     },
134 |   },
135 | });
136 | 
137 | async function main() {
138 |   const transport = new StdioServerTransport();
139 |   await server.connect(transport);
140 |   console.error('Stripe MCP Server running on stdio');
141 | }
142 | 
143 | main().catch((error) => {
144 |   console.error('Fatal error in main():', error);
145 |   process.exit(1);
146 | });
147 | ```
148 | 
149 | [node-sdk]: https://github.com/stripe/stripe-node
150 | [api-keys]: https://dashboard.stripe.com/account/apikeys
151 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Stripe Model Context Protocol
  2 | 
  3 | The Stripe [Model Context Protocol](https://modelcontextprotocol.com/) server allows you to integrate with Stripe APIs through function calling. This protocol supports various tools to interact with different Stripe services.
  4 | 
  5 | ## Setup
  6 | 
  7 | Stripe hosts a remote MCP server at https://mcp.stripe.com. View the docs [here](https://docs.stripe.com/mcp). To run the Stripe MCP server locally using npx, use the following command:
  8 | 
  9 | ```bash
 10 | # To set up all available tools
 11 | npx -y @stripe/mcp --tools=all --api-key=YOUR_STRIPE_SECRET_KEY
 12 | 
 13 | # To set up specific tools
 14 | npx -y @stripe/mcp --tools=customers.create,customers.read,products.create --api-key=YOUR_STRIPE_SECRET_KEY
 15 | 
 16 | # To configure a Stripe connected account
 17 | npx -y @stripe/mcp --tools=all --api-key=YOUR_STRIPE_SECRET_KEY --stripe-account=CONNECTED_ACCOUNT_ID
 18 | ```
 19 | 
 20 | Make sure to replace `YOUR_STRIPE_SECRET_KEY` with your actual Stripe secret key. Alternatively, you could set the STRIPE_SECRET_KEY in your environment variables.
 21 | 
 22 | ### Usage with Claude Desktop
 23 | 
 24 | Add the following to your `claude_desktop_config.json`. See [here](https://modelcontextprotocol.io/quickstart/user) for more details.
 25 | 
 26 | ```
 27 | {
 28 |   "mcpServers": {
 29 |     "stripe": {
 30 |       "command": "npx",
 31 |       "args": [
 32 |           "-y",
 33 |           "@stripe/mcp",
 34 |           "--tools=all",
 35 |           "--api-key=STRIPE_SECRET_KEY"
 36 |       ]
 37 |     }
 38 |   }
 39 | }
 40 | ```
 41 | 
 42 | of if you're using Docker
 43 | 
 44 | ```
 45 | {
 46 |     “mcpServers”: {
 47 |         “stripe”: {
 48 |             “command”: “docker",
 49 |             “args”: [
 50 |                 “run”,
 51 |                 "--rm",
 52 |                 "-i",
 53 |                 “mcp/stripe”,
 54 |                 “--tools=all”,
 55 |                 “--api-key=STRIPE_SECRET_KEY”
 56 |             ]
 57 |         }
 58 |     }
 59 | }
 60 | 
 61 | ```
 62 | 
 63 | ### Usage with Gemini CLI
 64 | 
 65 | 1. Install [Gemini CLI](https://google-gemini.github.io/gemini-cli/#-installation) through your preferred method.
 66 | 2. Install the Stripe MCP extension: `gemini extensions install https://github.com/stripe/agent-toolkit`.
 67 | 3. Start Gemini CLI: `gemini`.
 68 | 4. Go through the OAUTH flow: `/mcp auth stripe`.
 69 | 
 70 | ## Available tools
 71 | 
 72 | | Tool                   | Description                     |
 73 | | ---------------------- | ------------------------------- |
 74 | | `balance.read`         | Retrieve balance information    |
 75 | | `coupons.create`       | Create a new coupon             |
 76 | | `coupons.read`         | Read coupon information         |
 77 | | `customers.create`     | Create a new customer           |
 78 | | `customers.read`       | Read customer information       |
 79 | | `disputes.read`        | Read disputes information       |
 80 | | `disputes.update`      | Update an existing dispute      |
 81 | | `documentation.read`   | Search Stripe documentation     |
 82 | | `invoiceItems.create`  | Create a new invoice item       |
 83 | | `invoices.create`      | Create a new invoice            |
 84 | | `invoices.read`        | Read invoice information        |
 85 | | `invoices.update`      | Update an existing invoice      |
 86 | | `paymentIntents.read`  | Read payment intent information |
 87 | | `paymentLinks.create`  | Create a new payment link       |
 88 | | `prices.create`        | Create a new price              |
 89 | | `prices.read`          | Read price information          |
 90 | | `products.create`      | Create a new product            |
 91 | | `products.read`        | Read product information        |
 92 | | `refunds.create`       | Create a new refund             |
 93 | | `subscriptions.read`   | Read subscription information   |
 94 | | `subscriptions.update` | Update subscription information |
 95 | 
 96 | ## Debugging the Server
 97 | 
 98 | To debug your server, you can use the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector).
 99 | 
100 | First build the server
101 | 
102 | ```
103 | npm run build
104 | ```
105 | 
106 | Run the following command in your terminal:
107 | 
108 | ```bash
109 | # Start MCP Inspector and server with all tools
110 | npx @modelcontextprotocol/inspector node dist/index.js --tools=all --api-key=YOUR_STRIPE_SECRET_KEY
111 | ```
112 | 
113 | ### Build using Docker
114 | 
115 | First build the server
116 | 
117 | ```
118 | docker build -t mcp/stripe .
119 | ```
120 | 
121 | Run the following command in your terminal:
122 | 
123 | ```bash
124 | docker run -p 3000:3000 -p 5173:5173 -v /var/run/docker.sock:/var/run/docker.sock mcp/inspector docker run --rm -i mcp/stripe --tools=all --api-key=YOUR_STRIPE_SECRET_KEY
125 | 
126 | ```
127 | 
128 | ### Instructions
129 | 
130 | 1. Replace `YOUR_STRIPE_SECRET_KEY` with your actual Stripe API secret key.
131 | 2. Run the command to start the MCP Inspector.
132 | 3. Open the MCP Inspector UI in your browser and click Connect to start the MCP server.
133 | 4. You can see the list of tools you selected and test each tool individually.
134 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Stripe Agent Toolkit
  2 | 
  3 | The Stripe Agent Toolkit enables popular agent frameworks including Model Context Protocol (MCP), OpenAI's Agent SDK, LangChain, CrewAI, and Vercel's AI SDK to integrate with Stripe APIs through function calling. The
  4 | library is not exhaustive of the entire Stripe API. It includes support for MCP, Python, and TypeScript and is built directly on top of the Stripe [Python][python-sdk] and [Node][node-sdk] SDKs.
  5 | 
  6 | Included below are basic instructions, but refer to the [MCP](/modelcontextprotocol) [Python](/python), [TypeScript](/typescript) packages for more information.
  7 | 
  8 | ## Model Context Protocol
  9 | 
 10 | Stripe hosts a remote MCP server at `https://mcp.stripe.com`. This allows secure MCP client access via OAuth. View the docs [here](https://docs.stripe.com/mcp#remote).
 11 | 
 12 | The Stripe Agent Toolkit also exposes tools in the [Model Context Protocol (MCP)](https://modelcontextprotocol.com/) format.  Or, to run a local Stripe MCP server using npx, use the following command:
 13 | 
 14 | ```bash
 15 | npx -y @stripe/mcp --tools=all --api-key=YOUR_STRIPE_SECRET_KEY
 16 | ```
 17 | 
 18 | ## Python
 19 | 
 20 | ### Installation
 21 | 
 22 | You don't need this source code unless you want to modify the package. If you just
 23 | want to use the package run:
 24 | 
 25 | ```sh
 26 | pip install stripe-agent-toolkit
 27 | ```
 28 | 
 29 | #### Requirements
 30 | 
 31 | - Python 3.11+
 32 | 
 33 | ### Usage
 34 | 
 35 | The library needs to be configured with your account's secret key which is
 36 | available in your [Stripe Dashboard][api-keys].
 37 | 
 38 | ```python
 39 | from stripe_agent_toolkit.openai.toolkit import StripeAgentToolkit
 40 | 
 41 | stripe_agent_toolkit = StripeAgentToolkit(
 42 |     secret_key="sk_test_...",
 43 |     configuration={
 44 |         "actions": {
 45 |             "payment_links": {
 46 |                 "create": True,
 47 |             },
 48 |         }
 49 |     },
 50 | )
 51 | ```
 52 | 
 53 | The toolkit works with OpenAI's Agent SDK, LangChain, and CrewAI and can be passed as a list of tools. For example:
 54 | 
 55 | ```python
 56 | from agents import Agent
 57 | 
 58 | stripe_agent = Agent(
 59 |     name="Stripe Agent",
 60 |     instructions="You are an expert at integrating with Stripe",
 61 |     tools=stripe_agent_toolkit.get_tools()
 62 | )
 63 | ```
 64 | 
 65 | Examples for OpenAI's Agent SDK,LangChain, and CrewAI are included in [/examples](/python/examples).
 66 | 
 67 | #### Context
 68 | 
 69 | In some cases you will want to provide values that serve as defaults when making requests. Currently, the `account` context value enables you to make API calls for your [connected accounts](https://docs.stripe.com/connect/authentication).
 70 | 
 71 | ```python
 72 | stripe_agent_toolkit = StripeAgentToolkit(
 73 |     secret_key="sk_test_...",
 74 |     configuration={
 75 |         "context": {
 76 |             "account": "acct_123"
 77 |         }
 78 |     }
 79 | )
 80 | ```
 81 | 
 82 | ## TypeScript
 83 | 
 84 | ### Installation
 85 | 
 86 | You don't need this source code unless you want to modify the package. If you just
 87 | want to use the package run:
 88 | 
 89 | ```
 90 | npm install @stripe/agent-toolkit
 91 | ```
 92 | 
 93 | #### Requirements
 94 | 
 95 | - Node 18+
 96 | 
 97 | ### Usage
 98 | 
 99 | The library needs to be configured with your account's secret key which is available in your [Stripe Dashboard][api-keys]. Additionally, `configuration` enables you to specify the types of actions that can be taken using the toolkit.
100 | 
101 | ```typescript
102 | import { StripeAgentToolkit } from "@stripe/agent-toolkit/langchain";
103 | 
104 | const stripeAgentToolkit = new StripeAgentToolkit({
105 |   secretKey: process.env.STRIPE_SECRET_KEY!,
106 |   configuration: {
107 |     actions: {
108 |       paymentLinks: {
109 |         create: true,
110 |       },
111 |     },
112 |   },
113 | });
114 | ```
115 | 
116 | #### Tools
117 | 
118 | The toolkit works with LangChain and Vercel's AI SDK and can be passed as a list of tools. For example:
119 | 
120 | ```typescript
121 | import { AgentExecutor, createStructuredChatAgent } from "langchain/agents";
122 | 
123 | const tools = stripeAgentToolkit.getTools();
124 | 
125 | const agent = await createStructuredChatAgent({
126 |   llm,
127 |   tools,
128 |   prompt,
129 | });
130 | 
131 | const agentExecutor = new AgentExecutor({
132 |   agent,
133 |   tools,
134 | });
135 | ```
136 | 
137 | #### Context
138 | 
139 | In some cases you will want to provide values that serve as defaults when making requests. Currently, the `account` context value enables you to make API calls for your [connected accounts](https://docs.stripe.com/connect/authentication).
140 | 
141 | ```typescript
142 | const stripeAgentToolkit = new StripeAgentToolkit({
143 |   secretKey: process.env.STRIPE_SECRET_KEY!,
144 |   configuration: {
145 |     context: {
146 |       account: "acct_123",
147 |     },
148 |   },
149 | });
150 | ```
151 | 
152 | #### Metered billing
153 | 
154 | For Vercel's AI SDK, you can use middleware to submit billing events for usage. All that is required is the customer ID and the input/output meters to bill.
155 | 
156 | ```typescript
157 | import { StripeAgentToolkit } from "@stripe/agent-toolkit/ai-sdk";
158 | import { openai } from "@ai-sdk/openai";
159 | import {
160 |   generateText,
161 |   experimental_wrapLanguageModel as wrapLanguageModel,
162 | } from "ai";
163 | 
164 | const stripeAgentToolkit = new StripeAgentToolkit({
165 |   secretKey: process.env.STRIPE_SECRET_KEY!,
166 |   configuration: {
167 |     actions: {
168 |       paymentLinks: {
169 |         create: true,
170 |       },
171 |     },
172 |   },
173 | });
174 | 
175 | const model = wrapLanguageModel({
176 |   model: openai("gpt-4o"),
177 |   middleware: stripeAgentToolkit.middleware({
178 |     billing: {
179 |       customer: "cus_123",
180 |       meters: {
181 |         input: "input_tokens",
182 |         output: "output_tokens",
183 |       },
184 |     },
185 |   }),
186 | });
187 | ```
188 | 
189 | 
190 | 
191 | ## Supported API methods
192 | 
193 | - [Cancel a subscription](https://docs.stripe.com/api/subscriptions/cancel)
194 | - [Create a coupon](https://docs.stripe.com/api/coupons/create)
195 | - [Create a customer](https://docs.stripe.com/api/customers/create)
196 | - [Create a payment link](https://docs.stripe.com/api/payment-link/create)
197 | - [Create a price](https://docs.stripe.com/api/prices/create)
198 | - [Create a product](https://docs.stripe.com/api/products/create)
199 | - [Create a refund](https://docs.stripe.com/api/refunds/create)
200 | - [Create an invoice item](https://docs.stripe.com/api/invoiceitems/create)
201 | - [Create an invoice](https://docs.stripe.com/api/invoices/create)
202 | - [Finalize an invoice](https://docs.stripe.com/api/invoices/finalize)
203 | - [List all coupons](https://docs.stripe.com/api/coupons/list)
204 | - [List all customers](https://docs.stripe.com/api/customers/list)
205 | - [List all disputes](https://docs.stripe.com/api/disputes/list)
206 | - [List all prices](https://docs.stripe.com/api/prices/list)
207 | - [List all products](https://docs.stripe.com/api/products/list)
208 | - [List all subscriptions](https://docs.stripe.com/api/subscriptions/list)
209 | - [Retrieve balance](https://docs.stripe.com/api/balance/balance_retrieve)
210 | - [Update a dispute](https://docs.stripe.com/api/disputes/update)
211 | - [Update a subscription](https://docs.stripe.com/api/subscriptions/update)
212 | 
213 | [python-sdk]: https://github.com/stripe/stripe-python
214 | [node-sdk]: https://github.com/stripe/stripe-node
215 | [api-keys]: https://dashboard.stripe.com/account/apikeys
216 | 
```

--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------

```markdown
1 | # Security Policy
2 | 
3 | ### Reporting a vulnerability
4 | 
5 | Please do not open GitHub issues or pull requests - this makes the problem immediately visible to everyone, including malicious actors.   
6 | 
7 | Security issues in this open-source project can be safely reported to Stripe's [Vulnerability Disclosure and Reward Program](https://stripe.com/docs/security/stripe#disclosure-and-reward-program).
8 | Stripe's security team will triage your report and respond according to its impact on Stripe users and systems.
9 | 
```

--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Contributing
 2 | 
 3 | Contributions of any kind are welcome! If you've found a bug or have a feature request, please feel free to [open an issue](/issues). 
 4 | 
 5 | <!-- We will try and respond to your issue or pull request within a week. -->
 6 | 
 7 | To make changes yourself, follow these steps:
 8 | 
 9 | 1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository and [clone](https://help.github.com/articles/cloning-a-repository/) it locally.
10 | <!-- 1. TODO add install step(s), e.g. "Run `npm install`" -->
11 | <!-- 1. TODO add build step(s), e.g. "Build the library using `npm run build`" -->
12 | 2. Make your changes
13 | <!-- 1. TODO add test step(s), e.g. "Test your changes with `npm test`" -->
14 | 3. Submit a [pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)
15 | 
16 | ## Contributor License Agreement ([CLA](https://en.wikipedia.org/wiki/Contributor_License_Agreement))
17 | 
18 | Once you have submitted a pull request, sign the CLA by clicking on the badge in the comment from [@CLAassistant](https://github.com/CLAassistant).
19 | 
20 | <img width="910" alt="image" src="https://user-images.githubusercontent.com/62121649/198740836-70aeb322-5755-49fc-af55-93c8e8a39058.png">
21 | 
22 | <br />
23 | Thanks for contributing to Stripe! :sparkles:
24 | 
```

--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Contributor Covenant Code of Conduct
 2 | 
 3 | ## Our Pledge
 4 | 
 5 | In the interest of fostering an open and welcoming environment, we as
 6 | contributors and maintainers pledge to make participation in our project and
 7 | our community a harassment-free experience for everyone, regardless of age, body
 8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
 9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 | 
12 | ## Our Standards
13 | 
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 | 
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 | 
23 | Examples of unacceptable behavior by participants include:
24 | 
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 |   advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 |   address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 |   professional setting
33 | 
34 | ## Our Responsibilities
35 | 
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 | 
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 | 
46 | ## Scope
47 | 
48 | This Code of Conduct applies within all project spaces, and it also applies when
49 | an individual is representing the project or its community in public spaces.
50 | Examples of representing a project or community include using an official
51 | project e-mail address, posting via an official social media account, or acting
52 | as an appointed representative at an online or offline event. Representation of
53 | a project may be further defined and clarified by project maintainers.
54 | 
55 | ## Enforcement
56 | 
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at [email protected]. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 | 
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 | 
68 | ## Attribution
69 | 
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 | 
73 | [homepage]: https://www.contributor-covenant.org
74 | 
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 | 
```

--------------------------------------------------------------------------------
/python/examples/langchain/__init__.py:
--------------------------------------------------------------------------------

```python
1 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/__init__.py:
--------------------------------------------------------------------------------

```python
1 | 
```

--------------------------------------------------------------------------------
/python/tests/__init__.py:
--------------------------------------------------------------------------------

```python
1 | 
```

--------------------------------------------------------------------------------
/typescript/pnpm-workspace.yaml:
--------------------------------------------------------------------------------

```yaml
1 | packages:
2 |   - '.'
3 |   - 'examples/*'
4 | 
```

--------------------------------------------------------------------------------
/typescript/src/ai-sdk/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | import StripeAgentToolkit from './toolkit';
2 | export {StripeAgentToolkit};
3 | 
```

--------------------------------------------------------------------------------
/typescript/src/langchain/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | import StripeAgentToolkit from './toolkit';
2 | export {StripeAgentToolkit};
3 | 
```

--------------------------------------------------------------------------------
/typescript/src/openai/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | import StripeAgentToolkit from './toolkit';
2 | export {StripeAgentToolkit};
3 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/strands/__init__.py:
--------------------------------------------------------------------------------

```python
1 | """Stripe Agent Toolkit for Strands."""
2 | 
3 | from .toolkit import StripeAgentToolkit
4 | 
5 | __all__ = ["StripeAgentToolkit"]
6 | 
```

--------------------------------------------------------------------------------
/typescript/src/modelcontextprotocol/index.ts:
--------------------------------------------------------------------------------

```typescript
1 | import StripeAgentToolkit from './toolkit';
2 | import {registerPaidTool} from './register-paid-tool';
3 | export {StripeAgentToolkit, registerPaidTool};
4 | 
```

--------------------------------------------------------------------------------
/typescript/examples/ai-sdk/tsconfig.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "extends": "../../tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "dist"
5 |   },
6 |   "include": ["index.ts"],
7 |   "exclude": ["node_modules", "dist"]
8 | }
9 | 
```

--------------------------------------------------------------------------------
/typescript/examples/langchain/tsconfig.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "extends": "../../tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "dist"
5 |   },
6 |   "include": ["index.ts"],
7 |   "exclude": ["node_modules", "dist"]
8 | }
9 | 
```

--------------------------------------------------------------------------------
/typescript/examples/openai/tsconfig.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "extends": "../../tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "dist"
5 |   },
6 |   "include": ["index.ts"],
7 |   "exclude": ["node_modules", "dist"]
8 | }
9 | 
```

--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "recommendations": [
3 |     "EditorConfig.editorconfig", // default
4 |     "ms-python.python", // intellisense
5 |     "ms-python.flake8", // linting
6 |     "charliermarsh.ruff" // formatting
7 |   ]
8 | }
9 | 
```

--------------------------------------------------------------------------------
/gemini-extension.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "stripe-gemini-mcp-extension",
 3 |   "version": "0.1.0",
 4 |   "mcpServers": {
 5 |     "stripe": {
 6 |       "httpUrl": "https://mcp.stripe.com",
 7 |       "oauth": {
 8 |         "enabled": true
 9 |       }
10 |     }
11 |   }
12 | }
13 | 
```

--------------------------------------------------------------------------------
/python/requirements.txt:
--------------------------------------------------------------------------------

```
 1 | twine
 2 | crewai==0.76.2
 3 | crewai-tools===0.13.2
 4 | flake8
 5 | langchain==0.3.4
 6 | langchain-openai==0.2.2
 7 | mypy==1.7.0
 8 | pydantic>=2.10
 9 | pyright==1.1.350
10 | python-dotenv==1.0.1
11 | ruff==0.4.4
12 | stripe==11.0.0
13 | openai==1.66.0
14 | openai-agents==0.0.2
15 | 
```

--------------------------------------------------------------------------------
/typescript/examples/cloudflare/src/imageGenerator.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // @ts-ignore
 2 | import emojiFromText from 'emoji-from-text';
 3 | 
 4 | export function generateImage(description: string) {
 5 |   const emoji = emojiFromText(description);
 6 |   try {
 7 |     return emoji[0].match.emoji.char;
 8 |   } catch (e) {
 9 |     return '⚠️ (Error generating image)';
10 |   }
11 | }
12 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/jest.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type {Config} from 'jest';
 2 | 
 3 | const config: Config = {
 4 |   preset: 'ts-jest',
 5 |   testEnvironment: 'node',
 6 |   roots: ['<rootDir>/src'],
 7 |   testMatch: ['**/test/**/*.ts?(x)'],
 8 |   moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
 9 | };
10 | 
11 | export default config;
12 | 
```

--------------------------------------------------------------------------------
/typescript/jest.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type {Config} from 'jest';
 2 | 
 3 | const config: Config = {
 4 |   preset: 'ts-jest',
 5 |   testEnvironment: 'node',
 6 |   roots: ['<rootDir>/src'],
 7 |   testMatch: ['**/test/**/*.ts?(x)'],
 8 |   moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
 9 |   moduleNameMapper: {
10 |     '^@/(.*)$': '<rootDir>/src/$1',
11 |   },
12 | };
13 | 
14 | export default config;
15 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "outDir": "./dist",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------

```yaml
1 | blank_issues_enabled: false
2 | contact_links:
3 |   - name: Stripe support
4 |     url: https://support.stripe.com/
5 |     about: |
6 |       Please only file issues here that you believe represent actual bugs or feature requests for the Stripe Agent Tools library.
7 | 
8 |       If you're having general trouble with your Stripe integration, please reach out to support.
9 | 
```

--------------------------------------------------------------------------------
/python/examples/openai/customer_support/env.py:
--------------------------------------------------------------------------------

```python
 1 | from os import getenv
 2 | 
 3 | from dotenv import load_dotenv
 4 | 
 5 | # Load the environment
 6 | load_dotenv()
 7 | 
 8 | 
 9 | def ensure(name: str) -> str:
10 |     var = getenv(name)
11 |     if not var:
12 |         raise ValueError(f"Missing '{name}' environment variable")
13 |     return var
14 | 
15 | 
16 | def get_or(name: str, default: str) -> str:
17 |     var = getenv(name)
18 |     if not var:
19 |         return default
20 |     return var
21 | 
```

--------------------------------------------------------------------------------
/evals/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "$schema": "https://json.schemastore.org/tsconfig",
 3 |   "compilerOptions": {
 4 |     "target": "es2022",
 5 |     "module": "NodeNext",
 6 |     "moduleResolution": "NodeNext",
 7 |     "esModuleInterop": true,
 8 |     "skipLibCheck": true,
 9 |     "strict": true,
10 |     "baseUrl": ".",
11 |     "paths": {
12 |       "@/*": ["../typescript/src/*"]
13 |     }
14 |   },
15 |   "include": ["**/*.ts"],
16 |   "exclude": ["node_modules"]
17 | }
18 | 
```

--------------------------------------------------------------------------------
/typescript/examples/openai/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "stripe-agent-toolkit-examples-openai",
 3 |   "version": "0.1.0",
 4 |   "description": "",
 5 |   "main": "index.js",
 6 |   "scripts": {
 7 |     "test": "echo \"Error: no test specified\" && exit 1"
 8 |   },
 9 |   "author": "",
10 |   "license": "MIT",
11 |   "dependencies": {
12 |     "dotenv": "^16.4.5",
13 |     "openai": "^4.86.1",
14 |     "@stripe/agent-toolkit": "latest"
15 |   },
16 |   "devDependencies": {
17 |     "@types/node": "^22.7.4"
18 |   }
19 | }
20 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # syntax=docker/dockerfile:1
 2 | # check=experimental=all
 3 | 
 4 | FROM node:22-alpine@sha256:9bef0ef1e268f60627da9ba7d7605e8831d5b56ad07487d24d1aa386336d1944
 5 | RUN npm install -g typescript pnpm
 6 | RUN addgroup -S group && adduser -S user -G group
 7 | WORKDIR /app
 8 | COPY . .
 9 | RUN --mount=type=cache,target=/root/.local \
10 |     pnpm install --frozen-lockfile && pnpm run build
11 | 
12 | USER user
13 | ENTRYPOINT ["node", "/app/dist/index.js"]
14 | 
```

--------------------------------------------------------------------------------
/typescript/examples/ai-sdk/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "stripe-agent-toolkit-examples-ai-sdk",
 3 |   "version": "0.1.0",
 4 |   "description": "",
 5 |   "scripts": {
 6 |     "test": "echo \"Error: no test specified\" && exit 1"
 7 |   },
 8 |   "author": "",
 9 |   "license": "MIT",
10 |   "dependencies": {
11 |     "@ai-sdk/openai": "^0.0.63",
12 |     "@stripe/agent-toolkit": "latest",
13 |     "ai": "^3.4.7 || ^4.0.0",
14 |     "dotenv": "^16.4.5"
15 |   },
16 |   "devDependencies": {
17 |     "@types/node": "^22.7.4"
18 |   }
19 | }
20 | 
```

--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "editor.formatOnSave": true,
 3 |   "python.defaultInterpreterPath": "./venv/bin/python",
 4 |   "[python]": {
 5 |     "editor.defaultFormatter": "charliermarsh.ruff",
 6 |     "editor.codeActionsOnSave": {
 7 |       "source.organizeImports": "never"
 8 |     }
 9 |   },
10 |   "[typescript]": {
11 |     "editor.defaultFormatter": "esbenp.prettier-vscode"
12 |   },
13 |   "[json]": {
14 |     "editor.defaultFormatter": "esbenp.prettier-vscode"
15 |   },
16 |   "ruff.lint.enable": false
17 | }
18 | 
```

--------------------------------------------------------------------------------
/python/examples/openai/customer_support/pyproject.toml:
--------------------------------------------------------------------------------

```toml
 1 | [project]
 2 | name = "email-agent"
 3 | version = "0.1.0"
 4 | description = "An automated email support agent that uses AI to respond to customer support emails"
 5 | requires-python = ">=3.9"
 6 | dependencies = [
 7 |     "python-dotenv>=1.0.0",
 8 |     "imaplib2==3.6",
 9 |     "python-decouple==3.8",
10 |     "openai-agents==0.0.2",
11 |     "stripe-agent-toolkit>=0.6.0",
12 |     "stripe>=7.0.0",
13 |     "urllib3<2.0.0",
14 |     "markdown==3.7"
15 | ]
16 | 
17 | [tool.hatch.metadata]
18 | allow-direct-references = true
19 | 
```

--------------------------------------------------------------------------------
/typescript/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "$schema": "https://json.schemastore.org/tsconfig",
 3 |   "display": "Default",
 4 |   "compilerOptions": {
 5 |     "outDir": "./dist",
 6 |     "target": "es2022",
 7 |     "moduleDetection": "force",
 8 |     "esModuleInterop": true,
 9 |     "skipLibCheck": true,
10 |     "strict": true,
11 |     "module": "NodeNext",
12 |     "baseUrl": ".",
13 |     "paths": {
14 |       "@/*": [
15 |         "src/*"
16 |       ]
17 |     }
18 |   },
19 |   "include": [
20 |     "**/*.ts"
21 |   ],
22 |   "exclude": [
23 |     "node_modules",
24 |     "examples"
25 |   ]
26 | }
```

--------------------------------------------------------------------------------
/typescript/src/ai-sdk/tool.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type {CoreTool} from 'ai';
 2 | import {tool} from 'ai';
 3 | import {z} from 'zod';
 4 | import StripeAPI from '../shared/api';
 5 | 
 6 | export default function StripeTool(
 7 |   stripeAPI: StripeAPI,
 8 |   method: string,
 9 |   description: string,
10 |   schema: z.ZodObject<any, any, any, any, {[x: string]: any}>
11 | ): CoreTool {
12 |   return tool({
13 |     description: description,
14 |     parameters: schema,
15 |     execute: (arg: z.output<typeof schema>) => {
16 |       return stripeAPI.run(method, arg);
17 |     },
18 |   });
19 | }
20 | 
```

--------------------------------------------------------------------------------
/typescript/examples/langchain/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "stripe-agent-toolkit-examples-langchain",
 3 |   "version": "0.1.0",
 4 |   "description": "",
 5 |   "main": "index.js",
 6 |   "scripts": {
 7 |     "test": "echo \"Error: no test specified\" && exit 1"
 8 |   },
 9 |   "author": "",
10 |   "license": "MIT",
11 |   "dependencies": {
12 |     "@langchain/core": "^0.3.6",
13 |     "@langchain/openai": "^0.3.5",
14 |     "@stripe/agent-toolkit": "latest",
15 |     "dotenv": "^16.4.5",
16 |     "langchain": "^0.3.2"
17 |   },
18 |   "devDependencies": {
19 |     "@types/node": "^22.7.4"
20 |   }
21 | }
22 | 
```

--------------------------------------------------------------------------------
/typescript/examples/cloudflare/biome.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
 3 |   "vcs": {
 4 |     "enabled": false,
 5 |     "clientKind": "git",
 6 |     "useIgnoreFile": false
 7 |   },
 8 |   "files": {
 9 |     "ignoreUnknown": false,
10 |     "ignore": ["worker-configuration.d.ts"]
11 |   },
12 |   "formatter": {
13 |     "enabled": true,
14 |     "indentStyle": "tab"
15 |   },
16 |   "organizeImports": {
17 |     "enabled": true
18 |   },
19 |   "linter": {
20 |     "enabled": true,
21 |     "rules": {
22 |       "recommended": true
23 |     }
24 |   },
25 |   "javascript": {
26 |     "formatter": {
27 |       "quoteStyle": "double"
28 |     }
29 |   }
30 | }
31 | 
```

--------------------------------------------------------------------------------
/typescript/examples/cloudflare/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "es2021",
 4 |     "lib": [
 5 |       "es2021"
 6 |     ],
 7 |     "jsx": "react-jsx",
 8 |     "module": "es2022",
 9 |     "moduleResolution": "Bundler",
10 |     "resolveJsonModule": true,
11 |     "allowJs": true,
12 |     "checkJs": false,
13 |     "noEmit": true,
14 |     "isolatedModules": true,
15 |     "allowSyntheticDefaultImports": true,
16 |     "forceConsistentCasingInFileNames": true,
17 |     "allowImportingTsExtensions": true,
18 |     "strict": true,
19 |     "skipLibCheck": true,
20 |     "types": []
21 |   },
22 |   "include": [
23 |     "worker-configuration.d.ts",
24 |     "src/**/*.ts"
25 |   ]
26 | }
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/invoiceItems/prompts.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createInvoiceItemPrompt} from '@/shared/invoiceItems/createInvoiceItem';
 2 | 
 3 | describe('createInvoiceItemPrompt', () => {
 4 |   it('should return the correct prompt when no customer is specified', () => {
 5 |     const prompt = createInvoiceItemPrompt({});
 6 |     expect(prompt).toContain('- customer (str)');
 7 |   });
 8 | 
 9 |   it('should return the correct prompt when a customer is specified', () => {
10 |     const prompt = createInvoiceItemPrompt({customer: 'cus_123'});
11 |     expect(prompt).toContain('context: cus_123');
12 |     expect(prompt).not.toContain('- customer (str)');
13 |   });
14 | });
15 | 
```

--------------------------------------------------------------------------------
/evals/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "evals",
 3 |   "version": "1.0.0",
 4 |   "description": "",
 5 |   "main": "index.js",
 6 |   "scripts": {
 7 |     "test": "tsx eval.ts"
 8 |   },
 9 |   "keywords": [],
10 |   "author": "",
11 |   "license": "ISC",
12 |   "dependencies": {
13 |     "@ai-sdk/openai": "^0.0.63",
14 |     "@stripe/agent-toolkit": "file:../typescript",
15 |     "ai": "^4.0.28",
16 |     "autoevals": "^0.0.124",
17 |     "braintrust": "^0.0.185",
18 |     "dotenv": "^16.4.7",
19 |     "lodash": "^4.17.21",
20 |     "openai": "^4.91.1",
21 |     "stripe": "^17.7.0",
22 |     "zod": "^3.24.2"
23 |   },
24 |   "devDependencies": {
25 |     "@types/lodash": "^4.17.20",
26 |     "tsx": "^4.19.3"
27 |   }
28 | }
29 | 
```

--------------------------------------------------------------------------------
/python/examples/openai/customer_support/repl.py:
--------------------------------------------------------------------------------

```python
 1 | import asyncio
 2 | 
 3 | from agents import ItemHelpers, TResponseInputItem
 4 | 
 5 | import support_agent
 6 | 
 7 | 
 8 | async def main():
 9 |     """Simple REPL for testing your support agent"""
10 |     input_items: list[TResponseInputItem] = []
11 |     while True:
12 |         user_input = input("Enter your message: ")
13 |         input_items.append({"content": user_input, "role": "user"})
14 |         result = await support_agent.run(input_items)
15 |         output = ItemHelpers.text_message_outputs(result.new_items)
16 |         print(f"Assistant: {output}")
17 |         input_items = result.to_input_list()
18 | 
19 | 
20 | if __name__ == "__main__":
21 |     asyncio.run(main())
22 | 
```

--------------------------------------------------------------------------------
/evals/braintrust_openai.ts:
--------------------------------------------------------------------------------

```typescript
 1 | require("dotenv").config();
 2 | 
 3 | import { wrapOpenAI } from "braintrust";
 4 | import OpenAI from "openai";
 5 | import * as http from "http";
 6 | import * as net from "net";
 7 | 
 8 | const httpAgent = process.env.SOCKET_PROXY_PATH
 9 |   ? new (class extends http.Agent {
10 |       createConnection = (_: any, callback: Function) =>
11 |         net.createConnection(process.env.SOCKET_PROXY_PATH!, () => callback());
12 |     })()
13 |   : undefined;
14 | 
15 | // This wrap function adds useful tracing in Braintrust
16 | const openai: any = wrapOpenAI(
17 |   new OpenAI({
18 |     baseURL: process.env.OPENAI_BASE_URL,
19 |     apiKey: process.env.OPENAI_API_KEY,
20 |     httpAgent,
21 |   })
22 | );
23 | 
24 | export default openai;
25 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/balance/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {retrieveBalanceParameters} from '@/shared/balance/retrieveBalance';
 2 | 
 3 | describe('retrieveBalanceParameters', () => {
 4 |   it('should return the correct parameters if no context', () => {
 5 |     const parameters = retrieveBalanceParameters({});
 6 | 
 7 |     const fields = Object.keys(parameters.shape);
 8 |     expect(fields).toEqual([]);
 9 |     expect(fields.length).toBe(0);
10 |   });
11 | 
12 |   it('should return the correct parameters if customer is specified', () => {
13 |     const parameters = retrieveBalanceParameters({customer: 'cus_123'});
14 | 
15 |     const fields = Object.keys(parameters.shape);
16 |     expect(fields).toEqual([]);
17 |     expect(fields.length).toBe(0);
18 |   });
19 | });
20 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/crewai/tool.py:
--------------------------------------------------------------------------------

```python
 1 | """
 2 | This tool allows agents to interact with the Stripe API.
 3 | """
 4 | 
 5 | from __future__ import annotations
 6 | 
 7 | from typing import Any, Optional, Type
 8 | from pydantic import BaseModel
 9 | 
10 | from crewai_tools import BaseTool
11 | 
12 | from ..api import StripeAPI
13 | 
14 | 
15 | class StripeTool(BaseTool):
16 |     """Tool for interacting with the Stripe API."""
17 | 
18 |     stripe_api: StripeAPI
19 |     method: str
20 |     name: str = ""
21 |     description: str = ""
22 |     args_schema: Optional[Type[BaseModel]] = None
23 | 
24 |     def _run(
25 |         self,
26 |         *args: Any,
27 |         **kwargs: Any,
28 |     ) -> str:
29 |         """Use the Stripe API to run an operation."""
30 |         return self.stripe_api.run(self.method, *args, **kwargs)
31 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/langchain/tool.py:
--------------------------------------------------------------------------------

```python
 1 | """
 2 | This tool allows agents to interact with the Stripe API.
 3 | """
 4 | 
 5 | from __future__ import annotations
 6 | 
 7 | from typing import Any, Optional, Type
 8 | from pydantic import BaseModel
 9 | 
10 | from langchain.tools import BaseTool
11 | 
12 | from ..api import StripeAPI
13 | 
14 | 
15 | class StripeTool(BaseTool):
16 |     """Tool for interacting with the Stripe API."""
17 | 
18 |     stripe_api: StripeAPI
19 |     method: str
20 |     name: str = ""
21 |     description: str = ""
22 |     args_schema: Optional[Type[BaseModel]] = None
23 | 
24 |     def _run(
25 |         self,
26 |         *args: Any,
27 |         **kwargs: Any,
28 |     ) -> str:
29 |         """Use the Stripe API to run an operation."""
30 |         return self.stripe_api.run(self.method, *args, **kwargs)
31 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/refunds/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createRefundParameters} from '@/shared/refunds/createRefund';
 2 | 
 3 | describe('createRefundParameters', () => {
 4 |   it('should return the correct parameters if no context', () => {
 5 |     const parameters = createRefundParameters({});
 6 | 
 7 |     const fields = Object.keys(parameters.shape);
 8 |     expect(fields).toEqual(['payment_intent', 'amount']);
 9 |     expect(fields.length).toBe(2);
10 |   });
11 | 
12 |   it('should return the correct parameters if customer is specified', () => {
13 |     const parameters = createRefundParameters({customer: 'cus_123'});
14 | 
15 |     const fields = Object.keys(parameters.shape);
16 |     expect(fields).toEqual(['payment_intent', 'amount']);
17 |     expect(fields.length).toBe(2);
18 |   });
19 | });
20 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/paymentIntents/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {listPaymentIntentsParameters} from '@/shared/paymentIntents/listPaymentIntents';
 2 | 
 3 | describe('listPaymentIntentsParameters', () => {
 4 |   it('should return the correct parameters if no context', () => {
 5 |     const parameters = listPaymentIntentsParameters({});
 6 | 
 7 |     const fields = Object.keys(parameters.shape);
 8 |     expect(fields).toEqual(['customer', 'limit']);
 9 |     expect(fields.length).toBe(2);
10 |   });
11 | 
12 |   it('should return the correct parameters if customer is specified', () => {
13 |     const parameters = listPaymentIntentsParameters({customer: 'cus_123'});
14 | 
15 |     const fields = Object.keys(parameters.shape);
16 |     expect(fields).toEqual(['limit']);
17 |     expect(fields.length).toBe(1);
18 |   });
19 | });
20 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/paymentLinks/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createPaymentLinkParameters} from '@/shared/paymentLinks/createPaymentLink';
 2 | 
 3 | describe('createPaymentLinkParameters', () => {
 4 |   it('should return the correct parameters if no context', () => {
 5 |     const parameters = createPaymentLinkParameters({});
 6 | 
 7 |     const fields = Object.keys(parameters.shape);
 8 |     expect(fields).toEqual(['price', 'quantity', 'redirect_url']);
 9 |     expect(fields.length).toBe(3);
10 |   });
11 | 
12 |   it('should return the correct parameters if customer is specified', () => {
13 |     const parameters = createPaymentLinkParameters({customer: 'cus_123'});
14 | 
15 |     const fields = Object.keys(parameters.shape);
16 |     expect(fields).toEqual(['price', 'quantity', 'redirect_url']);
17 |   });
18 | });
19 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/invoiceItems/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createInvoiceItemParameters} from '@/shared/invoiceItems/createInvoiceItem';
 2 | 
 3 | describe('createInvoiceItemParameters', () => {
 4 |   it('should return the correct parameters if no context', () => {
 5 |     const parameters = createInvoiceItemParameters({});
 6 | 
 7 |     const fields = Object.keys(parameters.shape);
 8 |     expect(fields).toEqual(['customer', 'price', 'invoice']);
 9 |     expect(fields.length).toBe(3);
10 |   });
11 | 
12 |   it('should return the correct parameters if customer is specified', () => {
13 |     const parameters = createInvoiceItemParameters({customer: 'cus_123'});
14 | 
15 |     const fields = Object.keys(parameters.shape);
16 |     expect(fields).toEqual(['price', 'invoice']);
17 |     expect(fields.length).toBe(2);
18 |   });
19 | });
20 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/documentation/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {searchDocumentationParameters} from '@/shared/documentation/searchDocumentation';
 2 | 
 3 | describe('searchDocumentationParameters', () => {
 4 |   it('should return the correct parameters if no context', () => {
 5 |     const parameters = searchDocumentationParameters({});
 6 | 
 7 |     const fields = Object.keys(parameters.shape);
 8 |     expect(fields).toEqual(['question', 'language']);
 9 |     expect(fields.length).toBe(2);
10 |   });
11 | 
12 |   it('should return the correct parameters if customer is specified', () => {
13 |     const parameters = searchDocumentationParameters({customer: 'cus_123'});
14 | 
15 |     const fields = Object.keys(parameters.shape);
16 |     expect(fields).toEqual(['question', 'language']);
17 |     expect(fields.length).toBe(2);
18 |   });
19 | });
20 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/paymentIntents/prompts.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {listPaymentIntentsPrompt} from '@/shared/paymentIntents/listPaymentIntents';
 2 | 
 3 | describe('listPaymentIntentsPrompt', () => {
 4 |   it('should return the correct prompt', () => {
 5 |     const prompt = listPaymentIntentsPrompt();
 6 |     expect(prompt).toContain('customer');
 7 |   });
 8 | 
 9 |   it('should return the correct prompt when no customer is specified', () => {
10 |     const prompt = listPaymentIntentsPrompt({});
11 |     expect(prompt).toContain('- customer (str, optional)');
12 |   });
13 | 
14 |   it('should return the correct prompt when a customer is specified', () => {
15 |     const prompt = listPaymentIntentsPrompt({customer: 'cus_123'});
16 |     expect(prompt).toContain('context: cus_123');
17 |     expect(prompt).not.toContain('- customer (str, optional)');
18 |   });
19 | });
20 | 
```

--------------------------------------------------------------------------------
/.github/workflows/npm_mcp_release.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: NPM Release @stripe/mcp
 2 | 
 3 | on:
 4 |   workflow_dispatch: {}
 5 | 
 6 | jobs:
 7 |   mcp-release:
 8 |     runs-on: ubuntu-latest
 9 |     defaults:
10 |       run:
11 |         working-directory: ./modelcontextprotocol
12 |     permissions:
13 |       contents: read
14 |       id-token: write
15 |     steps:
16 |       - uses: actions/checkout@v4
17 | 
18 |       - name: pnpm
19 |         uses: pnpm/action-setup@v4
20 |         with:
21 |           version: 9.11.0
22 | 
23 |       # Setup .npmrc file to publish to npm
24 |       - uses: actions/setup-node@v4
25 |         with:
26 |           node-version: "20.x"
27 |           registry-url: "https://registry.npmjs.org"
28 |       - run: pnpm install
29 |       - run: pnpm run test
30 |       - run: pnpm run build
31 |       - run: npm publish --ignore-scripts --access public
32 |         env:
33 |           NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
34 | 
```

--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |     // Use IntelliSense to learn about possible attributes.
 3 |     // Hover to view descriptions of existing attributes.
 4 |     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
 5 |     "version": "0.2.0",
 6 |     "configurations": [
 7 |         {
 8 |             "type": "node",
 9 |             "request": "launch",
10 |             "name": "Jest Current File",
11 |             "runtimeExecutable": "sh",
12 |             "program": "${workspaceFolder}/typescript/node_modules/.bin/jest",
13 |             "args": [
14 |                 "${relativeFile}",
15 |                 "--config",
16 |                 "${workspaceFolder}/typescript/jest.config.ts"
17 |             ],
18 |             "console": "integratedTerminal",
19 |             "internalConsoleOptions": "openOnFirstSessionStart"
20 |         }
21 |     ]
22 | }
```

--------------------------------------------------------------------------------
/.github/workflows/npm_agent_toolkit_release.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: NPM Release @stripe/agent-toolkit
 2 | 
 3 | on:
 4 |   workflow_dispatch: {}
 5 | 
 6 | jobs:
 7 |   agent-toolkit-release:
 8 |     runs-on: ubuntu-latest
 9 |     defaults:
10 |       run:
11 |         working-directory: ./typescript
12 |     permissions:
13 |       contents: read
14 |       id-token: write
15 |     steps:
16 |       - uses: actions/checkout@v4
17 |       # Setup .npmrc file to publish to npm
18 | 
19 |       - name: pnpm
20 |         uses: pnpm/action-setup@v4
21 |         with:
22 |           version: 9.11.0
23 | 
24 |       - uses: actions/setup-node@v4
25 |         with:
26 |           node-version: "20.x"
27 |           registry-url: "https://registry.npmjs.org"
28 |       - run: pnpm install
29 |       - run: pnpm run test
30 |       - run: pnpm run build
31 |       - run: npm publish --ignore-scripts --access public
32 |         env:
33 |           NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
34 | 
```

--------------------------------------------------------------------------------
/typescript/tsup.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {defineConfig} from 'tsup';
 2 | 
 3 | export default defineConfig([
 4 |   {
 5 |     entry: ['src/langchain/index.ts'],
 6 |     outDir: 'langchain',
 7 |     format: ['cjs', 'esm'],
 8 |     dts: true,
 9 |     sourcemap: true,
10 |   },
11 |   {
12 |     entry: ['src/ai-sdk/index.ts'],
13 |     outDir: 'ai-sdk',
14 |     format: ['cjs', 'esm'],
15 |     dts: true,
16 |     sourcemap: true,
17 |   },
18 |   {
19 |     entry: ['src/modelcontextprotocol/index.ts'],
20 |     outDir: 'modelcontextprotocol',
21 |     format: ['cjs', 'esm'],
22 |     dts: true,
23 |     sourcemap: true,
24 |   },
25 |   {
26 |     entry: ['src/openai/index.ts'],
27 |     outDir: 'openai',
28 |     format: ['cjs', 'esm'],
29 |     dts: true,
30 |     sourcemap: true,
31 |   },
32 |   {
33 |     entry: ['src/cloudflare/index.ts'],
34 |     outDir: 'cloudflare',
35 |     format: ['cjs', 'esm'],
36 |     dts: true,
37 |     sourcemap: true,
38 |     external: ['cloudflare:workers'],
39 |   },
40 | ]);
41 | 
```

--------------------------------------------------------------------------------
/python/examples/openai/web_search/main.py:
--------------------------------------------------------------------------------

```python
 1 | import asyncio
 2 | import os
 3 | 
 4 | from dotenv import load_dotenv
 5 | load_dotenv()
 6 | 
 7 | from agents import Agent, Runner, WebSearchTool
 8 | from stripe_agent_toolkit.openai.toolkit import StripeAgentToolkit
 9 | 
10 | stripe_agent_toolkit = StripeAgentToolkit(
11 |     secret_key=os.getenv("STRIPE_SECRET_KEY"),
12 |     configuration={},
13 | )
14 | 
15 | research_agent = Agent(
16 |     name="Research Agent",
17 |     instructions="You are an expert at research.",
18 |     tools=[WebSearchTool()],
19 |     hooks=stripe_agent_toolkit.billing_hook(
20 |         type="outcome",
21 |         customer=os.getenv("STRIPE_CUSTOMER_ID"),
22 |         meter=os.getenv("STRIPE_METER"),
23 |     ),
24 | )
25 | 
26 | async def main():
27 |     result = await Runner.run(
28 |         research_agent,
29 |         "search the web for 'global gdp' and give me the latest data.",
30 |     )
31 |     print(result.final_output)
32 | 
33 | if __name__ == "__main__":
34 |     asyncio.run(main())
35 | 
```

--------------------------------------------------------------------------------
/typescript/examples/cloudflare/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "remote-mcp-server",
 3 |   "version": "0.0.0",
 4 |   "private": true,
 5 |   "scripts": {
 6 |     "deploy": "wrangler deploy",
 7 |     "dev": "wrangler dev",
 8 |     "format": "biome format --write",
 9 |     "lint:fix": "biome lint --fix",
10 |     "start": "wrangler dev",
11 |     "cf-typegen": "wrangler types"
12 |   },
13 |   "devDependencies": {
14 |     "@biomejs/biome": "1.9.4",
15 |     "@cloudflare/workers-types": "^4.20250515.0",
16 |     "typescript": "^5.8.3",
17 |     "workers-mcp": "0.1.0-3",
18 |     "wrangler": "^4.15.2"
19 |   },
20 |   "dependencies": {
21 |     "@cloudflare/workers-oauth-provider": "^0.0.5",
22 |     "@modelcontextprotocol/sdk": "1.11.3",
23 |     "@stripe/agent-toolkit": "latest",
24 |     "@types/node": "^22.15.18",
25 |     "add": "^2.0.6",
26 |     "agents": "^0.0.84",
27 |     "dotenv": "^16.5.0",
28 |     "emoji-from-text": "^1.1.13",
29 |     "hono": "^4.7.9",
30 |     "stripe": "^18.1.0",
31 |     "zod": "^3.24.4"
32 |   },
33 |   "pnpm": {}
34 | }
35 | 
```

--------------------------------------------------------------------------------
/python/examples/strands/main.py:
--------------------------------------------------------------------------------

```python
 1 | import os
 2 | from dotenv import load_dotenv
 3 | 
 4 | from strands import Agent
 5 | from stripe_agent_toolkit.strands.toolkit import StripeAgentToolkit
 6 | 
 7 | load_dotenv()
 8 | 
 9 | # Initialize the Stripe Agent Toolkit
10 | stripe_agent_toolkit = StripeAgentToolkit(
11 |     secret_key=os.getenv("STRIPE_SECRET_KEY"),
12 |     configuration={
13 |         "actions": {
14 |             "payment_links": {
15 |                 "create": True,
16 |             },
17 |             "products": {
18 |                 "create": True,
19 |             },
20 |             "prices": {
21 |                 "create": True,
22 |             },
23 |         }
24 |     },
25 | )
26 | 
27 | # Get the Stripe tools
28 | tools = stripe_agent_toolkit.get_tools()
29 | 
30 | # Create agent with Stripe tools
31 | agent = Agent(
32 |     tools=tools
33 | )
34 | 
35 | # Test the agent
36 | response = agent("""
37 |     Create a payment link for a new product called 'test' with a price
38 |     of $100. Come up with a funny description about buy bots,
39 |     maybe a haiku.
40 | """)
41 | 
42 | print(response)
43 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/openai/hooks.py:
--------------------------------------------------------------------------------

```python
 1 | from typing import Any
 2 | from agents import AgentHooks, RunContextWrapper, Agent, Tool
 3 | from ..api import StripeAPI
 4 | 
 5 | class BillingHooks(AgentHooks):
 6 |     def __init__(self, stripe: StripeAPI, type: str, customer: str, meter: str = None, meters: dict[str, str] = None):
 7 |         self.type = type
 8 |         self.stripe = stripe
 9 |         self.customer = customer
10 |         self.meter = meter
11 |         self.meters = meters
12 | 
13 |     async def on_end(self, context: RunContextWrapper, agent: Agent, output: Any) -> None:
14 |         if self.type == "outcome":
15 |             self.stripe.create_meter_event(self.meter, self.customer)
16 | 
17 |         if self.type == "token":
18 |             if self.meters["input"]:
19 |                 self.stripe.create_meter_event(self.meters["input"], self.customer, context.usage.input_tokens)
20 |             if self.meters["output"]:
21 |                 self.stripe.create_meter_event(self.meters["output"], self.customer, context.usage.output_tokens)
22 | 
```

--------------------------------------------------------------------------------
/typescript/src/langchain/tool.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {z} from 'zod';
 2 | import {StructuredTool} from '@langchain/core/tools';
 3 | import {CallbackManagerForToolRun} from '@langchain/core/callbacks/manager';
 4 | import {RunnableConfig} from '@langchain/core/runnables';
 5 | import StripeAPI from '../shared/api';
 6 | 
 7 | class StripeTool extends StructuredTool {
 8 |   stripeAPI: StripeAPI;
 9 | 
10 |   method: string;
11 | 
12 |   name: string;
13 | 
14 |   description: string;
15 | 
16 |   schema: z.ZodObject<any, any, any, any>;
17 | 
18 |   constructor(
19 |     StripeAPI: StripeAPI,
20 |     method: string,
21 |     description: string,
22 |     schema: z.ZodObject<any, any, any, any, {[x: string]: any}>
23 |   ) {
24 |     super();
25 | 
26 |     this.stripeAPI = StripeAPI;
27 |     this.method = method;
28 |     this.name = method;
29 |     this.description = description;
30 |     this.schema = schema;
31 |   }
32 | 
33 |   _call(
34 |     arg: z.output<typeof this.schema>,
35 |     _runManager?: CallbackManagerForToolRun,
36 |     _parentConfig?: RunnableConfig
37 |   ): Promise<any> {
38 |     return this.stripeAPI.run(this.method, arg);
39 |   }
40 | }
41 | 
42 | export default StripeTool;
43 | 
```

--------------------------------------------------------------------------------
/typescript/src/langchain/toolkit.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {BaseToolkit} from '@langchain/core/tools';
 2 | import StripeTool from './tool';
 3 | import StripeAPI from '../shared/api';
 4 | import tools from '../shared/tools';
 5 | import {isToolAllowed, type Configuration} from '../shared/configuration';
 6 | 
 7 | class StripeAgentToolkit implements BaseToolkit {
 8 |   private _stripe: StripeAPI;
 9 | 
10 |   tools: StripeTool[];
11 | 
12 |   constructor({
13 |     secretKey,
14 |     configuration,
15 |   }: {
16 |     secretKey: string;
17 |     configuration: Configuration;
18 |   }) {
19 |     this._stripe = new StripeAPI(secretKey, configuration.context);
20 | 
21 |     const context = configuration.context || {};
22 |     const filteredTools = tools(context).filter((tool) =>
23 |       isToolAllowed(tool, configuration)
24 |     );
25 | 
26 |     this.tools = filteredTools.map(
27 |       (tool) =>
28 |         new StripeTool(
29 |           this._stripe,
30 |           tool.method,
31 |           tool.description,
32 |           tool.parameters
33 |         )
34 |     );
35 |   }
36 | 
37 |   getTools(): StripeTool[] {
38 |     return this.tools;
39 |   }
40 | }
41 | 
42 | export default StripeAgentToolkit;
43 | 
```

--------------------------------------------------------------------------------
/python/pyproject.toml:
--------------------------------------------------------------------------------

```toml
 1 | [project]
 2 | name = "stripe-agent-toolkit"
 3 | version = "0.6.1"
 4 | description = "Stripe Agent Toolkit"
 5 | readme = "README.md"
 6 | license = {file = "LICENSE"}
 7 | authors = [
 8 |   {name = "Stripe", email = "[email protected]"}
 9 | ]
10 | keywords = ["stripe", "api", "payments"]
11 | 
12 | [project.urls]
13 | "Bug Tracker" = "https://github.com/stripe/agent-toolkit/issues"
14 | "Source Code" = "https://github.com/stripe/agent-toolkit"
15 | 
16 | [tool.setuptools.packages.find]
17 | include = ["stripe_agent_toolkit*"]
18 | exclude = ["tests*", "examples*"]
19 | 
20 | [tool.ruff]
21 | # same as our black config
22 | line-length = 79
23 | extend-exclude = ["build"]
24 | 
25 | [tool.ruff.format]
26 | # currently the default value, but opt-out in the future
27 | docstring-code-format = false
28 | 
29 | [tool.pyright]
30 | include = [
31 |   "*",
32 | ]
33 | exclude = ["build", "**/__pycache__"]
34 | reportMissingTypeArgument = true
35 | reportUnnecessaryCast = true
36 | reportUnnecessaryComparison = true
37 | reportUnnecessaryContains = true
38 | reportUnnecessaryIsInstance = true
39 | reportPrivateImportUsage = true
40 | reportUnnecessaryTypeIgnoreComment = true
41 | 
```

--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Feature request
 2 | description: Suggest an idea for this library
 3 | labels: ["feature-request"]
 4 | body:
 5 |   - type: markdown
 6 |     attributes:
 7 |       value: |
 8 |         Thanks for taking the time to fill out this feature request!
 9 |   - type: textarea
10 |     id: problem
11 |     attributes:
12 |       label: Is your feature request related to a problem? Please describe.
13 |       description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
14 |   - type: textarea
15 |     id: solution
16 |     attributes:
17 |       label: Describe the solution you'd like
18 |       description: A clear and concise description of what you want to happen.
19 |   - type: textarea
20 |     id: alternatives
21 |     attributes:
22 |       label: Describe alternatives you've considered
23 |       description: A clear and concise description of any alternative solutions or features you've considered.
24 |   - type: textarea
25 |     id: context
26 |     attributes:
27 |       label: Additional context
28 |       description: Add any other context about the feature request here.
29 | 
```

--------------------------------------------------------------------------------
/python/examples/langchain/main.py:
--------------------------------------------------------------------------------

```python
 1 | import os
 2 | from dotenv import load_dotenv
 3 | 
 4 | from langchain import hub
 5 | from langchain_openai import ChatOpenAI
 6 | 
 7 | from langgraph.prebuilt import create_react_agent
 8 | 
 9 | from stripe_agent_toolkit.langchain.toolkit import StripeAgentToolkit
10 | 
11 | load_dotenv()
12 | 
13 | llm = ChatOpenAI(
14 |     model="gpt-4o",
15 | )
16 | 
17 | stripe_agent_toolkit = StripeAgentToolkit(
18 |     secret_key=os.getenv("STRIPE_SECRET_KEY"),
19 |     configuration={
20 |         "actions": {
21 |             "payment_links": {
22 |                 "create": True,
23 |             },
24 |             "products": {
25 |                 "create": True,
26 |             },
27 |             "prices": {
28 |                 "create": True,
29 |             },
30 |         }
31 |     },
32 | )
33 | 
34 | tools = []
35 | tools.extend(stripe_agent_toolkit.get_tools())
36 | 
37 | langgraph_agent_executor = create_react_agent(llm, tools)
38 | 
39 | input_state = {
40 |     "messages": """
41 |         Create a payment link for a new product called 'test' with a price
42 |         of $100. Come up with a funny description about buy bots,
43 |         maybe a haiku.
44 |     """,
45 | }
46 | 
47 | output_state = langgraph_agent_executor.invoke(input_state)
48 | 
49 | print(output_state["messages"][-1].content)
50 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/crewai/toolkit.py:
--------------------------------------------------------------------------------

```python
 1 | """Stripe Agent Toolkit."""
 2 | 
 3 | from typing import List, Optional
 4 | from pydantic import PrivateAttr
 5 | 
 6 | from ..api import StripeAPI
 7 | from ..tools import tools
 8 | from ..configuration import Configuration, is_tool_allowed
 9 | from .tool import StripeTool
10 | 
11 | 
12 | class StripeAgentToolkit:
13 |     _tools: List = PrivateAttr(default=[])
14 | 
15 |     def __init__(
16 |         self, secret_key: str, configuration: Optional[Configuration] = None
17 |     ):
18 |         super().__init__()
19 | 
20 |         context = configuration.get("context") if configuration else None
21 | 
22 |         stripe_api = StripeAPI(secret_key=secret_key, context=context)
23 | 
24 |         filtered_tools = [
25 |             tool for tool in tools if is_tool_allowed(tool, configuration)
26 |         ]
27 | 
28 |         self._tools = [
29 |             StripeTool(
30 |                 name=tool["method"],
31 |                 description=tool["description"],
32 |                 method=tool["method"],
33 |                 stripe_api=stripe_api,
34 |                 args_schema=tool.get("args_schema", None),
35 |             )
36 |             for tool in filtered_tools
37 |         ]
38 | 
39 |     def get_tools(self) -> List:
40 |         """Get the tools in the toolkit."""
41 |         return self._tools
42 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/langchain/toolkit.py:
--------------------------------------------------------------------------------

```python
 1 | """Stripe Agent Toolkit."""
 2 | 
 3 | from typing import List, Optional
 4 | from pydantic import PrivateAttr
 5 | 
 6 | from ..api import StripeAPI
 7 | from ..tools import tools
 8 | from ..configuration import Configuration, Context, is_tool_allowed
 9 | from .tool import StripeTool
10 | 
11 | 
12 | class StripeAgentToolkit:
13 |     _tools: List = PrivateAttr(default=[])
14 | 
15 |     def __init__(
16 |         self, secret_key: str, configuration: Optional[Configuration] = None
17 |     ):
18 |         super().__init__()
19 | 
20 |         context = configuration.get("context") if configuration else None
21 | 
22 |         stripe_api = StripeAPI(secret_key=secret_key, context=context)
23 | 
24 |         filtered_tools = [
25 |             tool for tool in tools if is_tool_allowed(tool, configuration)
26 |         ]
27 | 
28 |         self._tools = [
29 |             StripeTool(
30 |                 name=tool["method"],
31 |                 description=tool["description"],
32 |                 method=tool["method"],
33 |                 stripe_api=stripe_api,
34 |                 args_schema=tool.get("args_schema", None),
35 |             )
36 |             for tool in filtered_tools
37 |         ]
38 | 
39 |     def get_tools(self) -> List:
40 |         """Get the tools in the toolkit."""
41 |         return self._tools
42 | 
```

--------------------------------------------------------------------------------
/typescript/examples/ai-sdk/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {StripeAgentToolkit} from '@stripe/agent-toolkit/ai-sdk';
 2 | import {openai} from '@ai-sdk/openai';
 3 | import {
 4 |   generateText,
 5 |   experimental_wrapLanguageModel as wrapLanguageModel,
 6 | } from 'ai';
 7 | 
 8 | require('dotenv').config();
 9 | 
10 | const stripeAgentToolkit = new StripeAgentToolkit({
11 |   secretKey: process.env.STRIPE_SECRET_KEY!,
12 |   configuration: {
13 |     actions: {
14 |       paymentLinks: {
15 |         create: true,
16 |       },
17 |       products: {
18 |         create: true,
19 |       },
20 |       prices: {
21 |         create: true,
22 |       },
23 |     },
24 |   },
25 | });
26 | 
27 | const model = wrapLanguageModel({
28 |   model: openai('gpt-4o'),
29 |   middleware: stripeAgentToolkit.middleware({
30 |     billing: {
31 |       customer: process.env.STRIPE_CUSTOMER_ID!,
32 |       meters: {
33 |         input: process.env.STRIPE_METER_INPUT!,
34 |         output: process.env.STRIPE_METER_OUTPUT!,
35 |       },
36 |     },
37 |   }),
38 | });
39 | 
40 | (async () => {
41 |   const result = await generateText({
42 |     model: model,
43 |     tools: {
44 |       ...stripeAgentToolkit.getTools(),
45 |     },
46 |     maxSteps: 5,
47 |     prompt:
48 |       'Create a payment link for a new product called "test" with a price of $100. Come up with a funny description about buy bots, maybe a haiku.',
49 |   });
50 | 
51 |   console.log(result);
52 | })();
53 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/strands/toolkit.py:
--------------------------------------------------------------------------------

```python
 1 | """Stripe Agent Toolkit."""
 2 | 
 3 | from typing import List, Optional, Dict
 4 | from strands.tools.tools import PythonAgentTool as StrandTool
 5 | 
 6 | from ..api import StripeAPI
 7 | from ..tools import tools
 8 | from ..configuration import Configuration, is_tool_allowed
 9 | from .tool import StripeTool
10 | from .hooks import BillingHooks
11 | 
12 | 
13 | class StripeAgentToolkit:
14 |     def __init__(
15 |         self, secret_key: str, configuration: Optional[Configuration] = None
16 |     ):
17 |         context = configuration.get("context") if configuration else None
18 | 
19 |         self._stripe_api = StripeAPI(secret_key=secret_key, context=context)
20 | 
21 |         filtered_tools = [
22 |             tool for tool in tools if is_tool_allowed(tool, configuration)
23 |         ]
24 | 
25 |         self._tools = [
26 |             StripeTool(self._stripe_api, tool)
27 |             for tool in filtered_tools
28 |         ]
29 | 
30 |     def get_tools(self) -> List[StrandTool]:
31 |         """Get the tools in the toolkit."""
32 |         return self._tools
33 | 
34 |     def billing_hook(
35 |         self,
36 |         type: Optional[str] = None,
37 |         customer: Optional[str] = None,
38 |         meter: Optional[str] = None,
39 |         meters: Optional[Dict[str, str]] = None
40 |     ) -> BillingHooks:
41 |         return BillingHooks(self._stripe_api, type, customer, meter, meters)
42 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/balance/functions.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {retrieveBalance} from '@/shared/balance/retrieveBalance';
 2 | 
 3 | const Stripe = jest.fn().mockImplementation(() => ({
 4 |   balance: {
 5 |     retrieve: jest.fn(),
 6 |   },
 7 | }));
 8 | 
 9 | let stripe: ReturnType<typeof Stripe>;
10 | 
11 | beforeEach(() => {
12 |   stripe = new Stripe('fake-api-key');
13 | });
14 | 
15 | describe('retrieveBalance', () => {
16 |   it('should retrieve the balance and return it', async () => {
17 |     const mockBalance = {available: [{amount: 1000, currency: 'usd'}]};
18 | 
19 |     const context = {};
20 | 
21 |     stripe.balance.retrieve.mockResolvedValue(mockBalance);
22 | 
23 |     const result = await retrieveBalance(stripe, context, {});
24 | 
25 |     expect(stripe.balance.retrieve).toHaveBeenCalledWith({}, undefined);
26 |     expect(result).toEqual(mockBalance);
27 |   });
28 | 
29 |   it('should specify the connected account if included in context', async () => {
30 |     const mockBalance = {available: [{amount: 1000, currency: 'usd'}]};
31 | 
32 |     const context = {
33 |       account: 'acct_123456',
34 |     };
35 | 
36 |     stripe.balance.retrieve.mockResolvedValue(mockBalance);
37 | 
38 |     const result = await retrieveBalance(stripe, context, {});
39 | 
40 |     expect(stripe.balance.retrieve).toHaveBeenCalledWith(
41 |       {},
42 |       {
43 |         stripeAccount: context.account,
44 |       }
45 |     );
46 |     expect(result).toEqual(mockBalance);
47 |   });
48 | });
49 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/paymentLinks/prompts.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createPaymentLinkPrompt} from '@/shared/paymentLinks/createPaymentLink';
 2 | 
 3 | describe('createPaymentLinkPrompt', () => {
 4 |   it('should return the correct prompt', () => {
 5 |     const prompt = createPaymentLinkPrompt({});
 6 | 
 7 |     expect(prompt).toContain('This tool will create a payment link in Stripe.');
 8 |     expect(prompt).toContain(
 9 |       'price (str): The ID of the price to create the payment link for.'
10 |     );
11 |     expect(prompt).toContain(
12 |       'quantity (int): The quantity of the product to include in the payment link.'
13 |     );
14 |     expect(prompt).toContain(
15 |       'redirect_url (str, optional): The URL to redirect to after the payment is completed.'
16 |     );
17 |   });
18 | 
19 |   it('should return the correct prompt with customer context', () => {
20 |     const prompt = createPaymentLinkPrompt({customer: 'cus_123'});
21 | 
22 |     expect(prompt).toContain('This tool will create a payment link in Stripe.');
23 |     expect(prompt).toContain(
24 |       'price (str): The ID of the price to create the payment link for.'
25 |     );
26 |     expect(prompt).toContain(
27 |       'quantity (int): The quantity of the product to include in the payment link.'
28 |     );
29 |     expect(prompt).toContain(
30 |       'redirect_url (str, optional): The URL to redirect to after the payment is completed.'
31 |     );
32 |   });
33 | });
34 | 
```

--------------------------------------------------------------------------------
/typescript/examples/langchain/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {StripeAgentToolkit} from '@stripe/agent-toolkit/langchain';
 2 | import {ChatOpenAI} from '@langchain/openai';
 3 | import type {ChatPromptTemplate} from '@langchain/core/prompts';
 4 | import {pull} from 'langchain/hub';
 5 | import {AgentExecutor, createStructuredChatAgent} from 'langchain/agents';
 6 | 
 7 | require('dotenv').config();
 8 | 
 9 | const llm = new ChatOpenAI({
10 |   model: 'gpt-4o',
11 | });
12 | 
13 | const stripeAgentToolkit = new StripeAgentToolkit({
14 |   secretKey: process.env.STRIPE_SECRET_KEY!,
15 |   configuration: {
16 |     actions: {
17 |       paymentLinks: {
18 |         create: true,
19 |       },
20 |       products: {
21 |         create: true,
22 |       },
23 |       prices: {
24 |         create: true,
25 |       },
26 |     },
27 |   },
28 | });
29 | 
30 | (async (): Promise<void> => {
31 |   const prompt = await pull<ChatPromptTemplate>(
32 |     'hwchase17/structured-chat-agent'
33 |   );
34 | 
35 |   const tools = stripeAgentToolkit.getTools();
36 | 
37 |   const agent = await createStructuredChatAgent({
38 |     llm,
39 |     tools,
40 |     prompt,
41 |   });
42 | 
43 |   const agentExecutor = new AgentExecutor({
44 |     agent,
45 |     tools,
46 |   });
47 | 
48 |   const response = await agentExecutor.invoke({
49 |     input: `
50 |       Create a payment link for a new product called 'test' with a price
51 |       of $100. Come up with a funny description about buy bots,
52 |       maybe a haiku.
53 |     `,
54 |   });
55 | 
56 |   console.log(response);
57 | })();
58 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/balance/retrieveBalance.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const retrieveBalancePrompt = (_context: Context = {}) => `
 7 | This tool will retrieve the balance from Stripe. It takes no input.
 8 | `;
 9 | 
10 | export const retrieveBalanceParameters = (
11 |   _context: Context = {}
12 | ): z.AnyZodObject => z.object({});
13 | 
14 | export const retrieveBalanceAnnotations = () => ({
15 |   destructiveHint: false,
16 |   idempotentHint: true,
17 |   openWorldHint: true,
18 |   readOnlyHint: true,
19 |   title: 'Retrieve balance',
20 | });
21 | 
22 | export const retrieveBalance = async (
23 |   stripe: Stripe,
24 |   context: Context,
25 |   params: z.infer<ReturnType<typeof retrieveBalanceParameters>>
26 | ) => {
27 |   try {
28 |     const balance = await stripe.balance.retrieve(
29 |       params,
30 |       context.account ? {stripeAccount: context.account} : undefined
31 |     );
32 | 
33 |     return balance;
34 |   } catch (error) {
35 |     return 'Failed to retrieve balance';
36 |   }
37 | };
38 | 
39 | const tool = (context: Context): Tool => ({
40 |   method: 'retrieve_balance',
41 |   name: 'Retrieve Balance',
42 |   description: retrieveBalancePrompt(context),
43 |   parameters: retrieveBalanceParameters(context),
44 |   annotations: retrieveBalanceAnnotations(),
45 |   actions: {
46 |     balance: {
47 |       read: true,
48 |     },
49 |   },
50 |   execute: retrieveBalance,
51 | });
52 | 
53 | export default tool;
54 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/openai/tool.py:
--------------------------------------------------------------------------------

```python
 1 | """
 2 | This tool allows agents to interact with the Stripe API.
 3 | """
 4 | 
 5 | from __future__ import annotations
 6 | 
 7 | from collections.abc import Awaitable
 8 | from typing import Any
 9 | import json
10 | 
11 | from agents import FunctionTool
12 | from agents.run_context import RunContextWrapper
13 | 
14 | def StripeTool(api, tool) -> FunctionTool:
15 |     async def on_invoke_tool(ctx: RunContextWrapper[Any], input_str: str) -> str:
16 |         return api.run(tool["method"], **json.loads(input_str))
17 | 
18 |     parameters = tool["args_schema"].model_json_schema()
19 |     parameters["additionalProperties"] = False
20 |     parameters["type"] = "object"
21 | 
22 |     # Remove the description field from parameters as it's not needed in the OpenAI function schema
23 |     if "description" in parameters:
24 |         del parameters["description"]
25 | 
26 |     if "title" in parameters:
27 |         del parameters["title"]
28 | 
29 |     # Remove title and default fields from properties
30 |     if "properties" in parameters:
31 |         for prop in parameters["properties"].values():
32 |             if "title" in prop:
33 |                 del prop["title"]
34 |             if "default" in prop:
35 |                 del prop["default"]
36 | 
37 |     return FunctionTool(
38 |         name=tool["method"],
39 |         description=tool["description"],
40 |         params_json_schema=parameters,
41 |         on_invoke_tool=on_invoke_tool,
42 |         strict_json_schema=False
43 |     )
44 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/products/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createProductParameters} from '@/shared/products/createProduct';
 2 | import {listProductsParameters} from '@/shared/products/listProducts';
 3 | 
 4 | describe('createProductParameters', () => {
 5 |   it('should return the correct parameters if no context', () => {
 6 |     const parameters = createProductParameters({});
 7 | 
 8 |     const fields = Object.keys(parameters.shape);
 9 |     expect(fields).toEqual(['name', 'description']);
10 |     expect(fields.length).toBe(2);
11 |   });
12 | 
13 |   it('should return the correct parameters if customer is specified', () => {
14 |     const parameters = createProductParameters({customer: 'cus_123'});
15 | 
16 |     const fields = Object.keys(parameters.shape);
17 |     expect(fields).toEqual(['name', 'description']);
18 |     expect(fields.length).toBe(2);
19 |   });
20 | });
21 | 
22 | describe('listProductsParameters', () => {
23 |   it('should return the correct parameters if no context', () => {
24 |     const parameters = listProductsParameters({});
25 | 
26 |     const fields = Object.keys(parameters.shape);
27 |     expect(fields).toEqual(['limit']);
28 |     expect(fields.length).toBe(1);
29 |   });
30 | 
31 |   it('should return the correct parameters if customer is specified', () => {
32 |     const parameters = listProductsParameters({customer: 'cus_123'});
33 | 
34 |     const fields = Object.keys(parameters.shape);
35 |     expect(fields).toEqual(['limit']);
36 |     expect(fields.length).toBe(1);
37 |   });
38 | });
39 | 
```

--------------------------------------------------------------------------------
/.github/workflows/pypi_release.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Python Release
 2 | 
 3 | on:
 4 |   workflow_dispatch: {}
 5 | 
 6 | jobs:
 7 |   python-build:
 8 |     name: Build for PyPi
 9 |     runs-on: ubuntu-latest
10 |     environment: pypi
11 | 
12 |     defaults:
13 |       run:
14 |         working-directory: ./python
15 | 
16 |     steps:
17 |       - name: Checkout
18 |         uses: actions/checkout@v4
19 | 
20 |       - name: Python
21 |         uses: actions/setup-python@v4
22 |         with:
23 |           python-version: "3.11"
24 | 
25 |       - name: Install
26 |         run: make venv
27 | 
28 |       - name: Build
29 |         run: |
30 |           set -x
31 |           source venv/bin/activate
32 |           rm -rf build dist *.egg-info
33 |           make build
34 |           python -m twine check dist/*
35 | 
36 |       - name: Test
37 |         run: |
38 |           make venv
39 |           make test
40 | 
41 |       - name: Upload artifact
42 |         uses: actions/upload-artifact@v4
43 |         with:
44 |           name: release-dists
45 |           path: ./python/dist/
46 | 
47 |   python-release:
48 |     name: Publish to PyPi
49 |     runs-on: ubuntu-latest
50 |     environment: pypi
51 |     needs:
52 |       - python-build
53 | 
54 |     defaults:
55 |       run:
56 |         working-directory: ./python
57 | 
58 |     permissions:
59 |       id-token: write
60 | 
61 |     steps:
62 |       - name: Retrieve distribution
63 |         uses: actions/download-artifact@v4
64 |         with:
65 |           name: release-dists
66 |           path: dist/
67 | 
68 |       - name: Publish package distributions to PyPI
69 |         uses: pypa/gh-action-pypi-publish@release/v1
70 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/openai/toolkit.py:
--------------------------------------------------------------------------------

```python
 1 | """Stripe Agent Toolkit."""
 2 | 
 3 | from typing import List, Optional
 4 | from pydantic import PrivateAttr
 5 | import json
 6 | 
 7 | from agents import FunctionTool
 8 | 
 9 | 
10 | from ..api import StripeAPI
11 | from ..tools import tools
12 | from ..configuration import Configuration, is_tool_allowed
13 | from .tool import StripeTool
14 | from .hooks import BillingHooks
15 | 
16 | class StripeAgentToolkit:
17 |     _tools: List[FunctionTool] = PrivateAttr(default=[])
18 |     _stripe_api: StripeAPI = PrivateAttr(default=None)
19 | 
20 |     def __init__(
21 |         self, secret_key: str, configuration: Optional[Configuration] = None
22 |     ):
23 |         super().__init__()
24 | 
25 |         context = configuration.get("context") if configuration else None
26 | 
27 |         self._stripe_api = StripeAPI(secret_key=secret_key, context=context)
28 | 
29 |         filtered_tools = [
30 |             tool for tool in tools if is_tool_allowed(tool, configuration)
31 |         ]
32 | 
33 |         self._tools = [
34 |             StripeTool(self._stripe_api, tool)
35 |             for tool in filtered_tools
36 |         ]
37 | 
38 |     def get_tools(self) -> List[FunctionTool]:
39 |         """Get the tools in the toolkit."""
40 |         return self._tools
41 | 
42 |     def billing_hook(self, type: Optional[str] = None, customer: Optional[str] = None, meter: Optional[str] = None, meters: Optional[dict[str, str]] = None) -> BillingHooks:
43 |         return BillingHooks(self._stripe_api, type, customer, meter, meters)
44 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/prices/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createPriceParameters} from '@/shared/prices/createPrice';
 2 | import {listPricesParameters} from '@/shared/prices/listPrices';
 3 | 
 4 | describe('createPriceParameters', () => {
 5 |   it('should return the correct parameters if no context', () => {
 6 |     const parameters = createPriceParameters({});
 7 | 
 8 |     const fields = Object.keys(parameters.shape);
 9 |     expect(fields).toEqual(['product', 'unit_amount', 'currency']);
10 |     expect(fields.length).toBe(3);
11 |   });
12 | 
13 |   it('should return the correct parameters if customer is specified', () => {
14 |     const parameters = createPriceParameters({customer: 'cus_123'});
15 | 
16 |     const fields = Object.keys(parameters.shape);
17 |     expect(fields).toEqual(['product', 'unit_amount', 'currency']);
18 |     expect(fields.length).toBe(3);
19 |   });
20 | });
21 | 
22 | describe('listPricesParameters', () => {
23 |   it('should return the correct parameters if no context', () => {
24 |     const parameters = listPricesParameters({});
25 | 
26 |     const fields = Object.keys(parameters.shape);
27 |     expect(fields).toEqual(['product', 'limit']);
28 |     expect(fields.length).toBe(2);
29 |   });
30 | 
31 |   it('should return the correct parameters if customer is specified', () => {
32 |     const parameters = listPricesParameters({customer: 'cus_123'});
33 | 
34 |     const fields = Object.keys(parameters.shape);
35 |     expect(fields).toEqual(['product', 'limit']);
36 |     expect(fields.length).toBe(2);
37 |   });
38 | });
39 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/invoices/prompts.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createInvoicePrompt} from '@/shared/invoices/createInvoice';
 2 | import {listInvoicesPrompt} from '@/shared/invoices/listInvoices';
 3 | import {finalizeInvoicePrompt} from '@/shared/invoices/finalizeInvoice';
 4 | 
 5 | describe('createInvoicePrompt', () => {
 6 |   it('should return the correct prompt when no customer is specified', () => {
 7 |     const prompt = createInvoicePrompt({});
 8 |     expect(prompt).toContain('- customer (str)');
 9 |   });
10 | 
11 |   it('should return the correct prompt when a customer is specified', () => {
12 |     const prompt = createInvoicePrompt({customer: 'cus_123'});
13 |     expect(prompt).toContain('context: cus_123');
14 |     expect(prompt).not.toContain('- customer (str)');
15 |   });
16 | });
17 | 
18 | describe('listInvoicesPrompt', () => {
19 |   it('should return the correct prompt when no customer is specified', () => {
20 |     const prompt = listInvoicesPrompt({});
21 |     expect(prompt).toContain('- customer (str, optional)');
22 |   });
23 | 
24 |   it('should return the correct prompt when a customer is specified', () => {
25 |     const prompt = listInvoicesPrompt({customer: 'cus_123'});
26 |     expect(prompt).toContain('context: cus_123');
27 |     expect(prompt).not.toContain('- customer (str, optional)');
28 |   });
29 | });
30 | 
31 | describe('finalizeInvoicePrompt', () => {
32 |   it('should return the correct prompt', () => {
33 |     const prompt = finalizeInvoicePrompt();
34 |     expect(prompt).toContain('invoice');
35 |   });
36 | });
37 | 
```

--------------------------------------------------------------------------------
/python/examples/openai/customer_support/support_agent.py:
--------------------------------------------------------------------------------

```python
 1 | import env
 2 | from agents import Agent, Runner, function_tool, TResponseInputItem, RunResult
 3 | from stripe_agent_toolkit.openai.toolkit import StripeAgentToolkit
 4 | import requests
 5 | 
 6 | env.ensure("OPENAI_API_KEY")
 7 | 
 8 | stripe_agent_toolkit = StripeAgentToolkit(
 9 |     secret_key=env.ensure("STRIPE_SECRET_KEY"),
10 |     configuration={
11 |         "actions": {
12 |             "customers": {
13 |                 "read": True,
14 |             },
15 |             "invoices": {
16 |                 "read": True,
17 |             },
18 |             "billing_portal_sessions": {
19 |                 "create": True,
20 |             },
21 |         }
22 |     },
23 | )
24 | 
25 | 
26 | @function_tool
27 | def search_faq(question: str) -> str:
28 |     response = requests.get("https://standupjack.com/faq")
29 |     if response.status_code != 200:
30 |         return "Not sure"
31 |     return f"Given the following context:\n{response.text}\n\nAnswer '{question}' or response with not sure\n"
32 | 
33 | 
34 | support_agent = Agent(
35 |     name="Standup Jack Agent",
36 |     instructions=(
37 |         "You are a helpful customer support assistant"
38 |         "Be casual and concise"
39 |         "You only respond with markdown"
40 |         "Use tools to support customers"
41 |         "Respond with I'm not sure to any other prompts"
42 |         "Sign off with Standup Jack Bot"
43 |     ),
44 |     tools=[search_faq, *stripe_agent_toolkit.get_tools()],
45 | )
46 | 
47 | 
48 | async def run(input: list[TResponseInputItem]) -> RunResult:
49 |     return await Runner.run(support_agent, input)
50 | 
```

--------------------------------------------------------------------------------
/typescript/examples/openai/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {StripeAgentToolkit} from '@stripe/agent-toolkit/openai';
 2 | import OpenAI from 'openai';
 3 | import type {ChatCompletionMessageParam} from 'openai/resources';
 4 | 
 5 | require('dotenv').config();
 6 | 
 7 | const openai = new OpenAI();
 8 | 
 9 | const stripeAgentToolkit = new StripeAgentToolkit({
10 |   secretKey: process.env.STRIPE_SECRET_KEY!,
11 |   configuration: {
12 |     actions: {
13 |       paymentLinks: {
14 |         create: true,
15 |       },
16 |       products: {
17 |         create: true,
18 |       },
19 |       prices: {
20 |         create: true,
21 |       },
22 |     },
23 |   },
24 | });
25 | 
26 | (async (): Promise<void> => {
27 |   let messages: ChatCompletionMessageParam[] = [
28 |     {
29 |       role: 'user',
30 |       content: `Create a payment link for a new product called 'test' with a price
31 | of $100. Come up with a funny description about buy bots,
32 | maybe a haiku.`,
33 |     },
34 |   ];
35 | 
36 |   while (true) {
37 |     // eslint-disable-next-line no-await-in-loop
38 |     const completion = await openai.chat.completions.create({
39 |       model: 'gpt-4o',
40 |       messages,
41 |       tools: stripeAgentToolkit.getTools(),
42 |     });
43 | 
44 |     const message = completion.choices[0].message;
45 | 
46 |     messages.push(message);
47 | 
48 |     if (message.tool_calls) {
49 |       // eslint-disable-next-line no-await-in-loop
50 |       const toolMessages = await Promise.all(
51 |         message.tool_calls.map((tc) => stripeAgentToolkit.handleToolCall(tc))
52 |       );
53 |       messages = [...messages, ...toolMessages];
54 |     } else {
55 |       console.log(completion.choices[0].message);
56 |       break;
57 |     }
58 |   }
59 | })();
60 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/customers/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createCustomerParameters} from '@/shared/customers/createCustomer';
 2 | import {listCustomersParameters} from '@/shared/customers/listCustomers';
 3 | 
 4 | describe('createCustomerParameters', () => {
 5 |   it('should return the correct parameters if no context', () => {
 6 |     // Create the parameters schema with an empty context
 7 |     const parameters = createCustomerParameters({});
 8 | 
 9 |     // Validate that the schema has the expected keys
10 |     const fields = Object.keys(parameters.shape);
11 |     expect(fields).toEqual(['name', 'email']);
12 |     expect(fields.length).toBe(2);
13 |   });
14 | 
15 |   it('should return the correct parameters if customer is specified', () => {
16 |     const parameters = createCustomerParameters({customer: 'cus_123'});
17 | 
18 |     const fields = Object.keys(parameters.shape);
19 |     expect(fields).toEqual(['name', 'email']);
20 |     expect(fields.length).toBe(2);
21 |   });
22 | });
23 | 
24 | describe('listCustomersParameters', () => {
25 |   it('should return the correct parameters if no context', () => {
26 |     const parameters = listCustomersParameters({});
27 | 
28 |     const fields = Object.keys(parameters.shape);
29 |     expect(fields).toEqual(['limit', 'email']);
30 |     expect(fields.length).toBe(2);
31 |   });
32 | 
33 |   it('should return the correct parameters if customer is specified', () => {
34 |     const parameters = listCustomersParameters({customer: 'cus_123'});
35 | 
36 |     const fields = Object.keys(parameters.shape);
37 |     expect(fields).toEqual(['limit', 'email']);
38 |     expect(fields.length).toBe(2);
39 |   });
40 | });
41 | 
```

--------------------------------------------------------------------------------
/python/examples/crewai/main.py:
--------------------------------------------------------------------------------

```python
 1 | import os
 2 | from dotenv import load_dotenv
 3 | 
 4 | from crewai import Agent, Task, Crew
 5 | from stripe_agent_toolkit.crewai.toolkit import StripeAgentToolkit
 6 | 
 7 | load_dotenv()
 8 | 
 9 | stripe_agent_toolkit = StripeAgentToolkit(
10 |     secret_key=os.getenv("STRIPE_SECRET_KEY"),
11 |     configuration={
12 |         "actions": {
13 |             "payment_links": {
14 |                 "create": True,
15 |             },
16 |             "products": {
17 |                 "create": True,
18 |             },
19 |             "prices": {
20 |                 "create": True,
21 |             },
22 |         }
23 |     },
24 | )
25 | 
26 | stripe_agent = Agent(
27 |     role="Stripe Agent",
28 |     goal="Integrate with Stripe effectively to support our business.",
29 |     backstory="You have been using stripe forever.",
30 |     tools=[*stripe_agent_toolkit.get_tools()],
31 |     allow_delegation=False,
32 |     verbose=True,
33 | )
34 | 
35 | haiku_writer = Agent(
36 |     role="Haiku writer",
37 |     goal="Write a haiku",
38 |     backstory="You are really good at writing haikus.",
39 |     allow_delegation=False,
40 |     verbose=True,
41 | )
42 | 
43 | create_payment_link = Task(
44 |     description="Create a payment link for a new product called 'test' "
45 |     "with a price of $100. The description should be a haiku",
46 |     expected_output="url",
47 |     agent=stripe_agent,
48 | )
49 | 
50 | write_haiku = Task(
51 |     description="Write a haiku about buy bots.",
52 |     expected_output="haiku",
53 |     agent=haiku_writer,
54 | )
55 | 
56 | crew = Crew(
57 |     agents=[stripe_agent, haiku_writer],
58 |     tasks=[create_payment_link, write_haiku],
59 |     verbose=True,
60 |     planning=True,
61 | )
62 | 
63 | crew.kickoff()
64 | 
```

--------------------------------------------------------------------------------
/typescript/src/modelcontextprotocol/toolkit.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';
 2 | import {RequestHandlerExtra} from '@modelcontextprotocol/sdk/shared/protocol.js';
 3 | import {Configuration, isToolAllowed} from '../shared/configuration';
 4 | import StripeAPI from '../shared/api';
 5 | import tools from '../shared/tools';
 6 | 
 7 | class StripeAgentToolkit extends McpServer {
 8 |   private _stripe: StripeAPI;
 9 | 
10 |   constructor({
11 |     secretKey,
12 |     configuration,
13 |   }: {
14 |     secretKey: string;
15 |     configuration: Configuration;
16 |   }) {
17 |     super({
18 |       name: 'Stripe',
19 |       version: '0.4.0',
20 |       configuration: {
21 |         ...configuration,
22 |         context: {
23 |           ...configuration.context,
24 |           mode: 'modelcontextprotocol',
25 |         },
26 |       },
27 |     });
28 | 
29 |     this._stripe = new StripeAPI(secretKey, configuration.context);
30 | 
31 |     const context = configuration.context || {};
32 |     const filteredTools = tools(context).filter((tool) =>
33 |       isToolAllowed(tool, configuration)
34 |     );
35 | 
36 |     filteredTools.forEach((tool) => {
37 |       this.tool(
38 |         tool.method,
39 |         tool.description,
40 |         tool.parameters.shape,
41 |         tool.annotations,
42 |         async (arg: any, _extra: RequestHandlerExtra<any, any>) => {
43 |           const result = await this._stripe.run(tool.method, arg);
44 |           return {
45 |             content: [
46 |               {
47 |                 type: 'text' as const,
48 |                 text: String(result),
49 |               },
50 |             ],
51 |           };
52 |         }
53 |       );
54 |     });
55 |   }
56 | }
57 | 
58 | export default StripeAgentToolkit;
59 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/api.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | 
 3 | import type {Context} from './configuration';
 4 | import tools, {Tool} from './tools';
 5 | 
 6 | const TOOLKIT_HEADER = 'stripe-agent-toolkit-typescript';
 7 | const MCP_HEADER = 'stripe-mcp';
 8 | 
 9 | class StripeAPI {
10 |   stripe: Stripe;
11 | 
12 |   context: Context;
13 | 
14 |   tools: Tool[];
15 | 
16 |   constructor(secretKey: string, context?: Context) {
17 |     const stripeClient = new Stripe(secretKey, {
18 |       appInfo: {
19 |         name:
20 |           context?.mode === 'modelcontextprotocol'
21 |             ? MCP_HEADER
22 |             : TOOLKIT_HEADER,
23 |         version: '0.7.11',
24 |         url: 'https://github.com/stripe/agent-toolkit',
25 |       },
26 |     });
27 |     this.stripe = stripeClient;
28 |     this.context = context || {};
29 |     this.tools = tools(this.context);
30 |   }
31 | 
32 |   async createMeterEvent({
33 |     event,
34 |     customer,
35 |     value,
36 |   }: {
37 |     event: string;
38 |     customer: string;
39 |     value: string;
40 |   }) {
41 |     await this.stripe.billing.meterEvents.create(
42 |       {
43 |         event_name: event,
44 |         payload: {
45 |           stripe_customer_id: customer,
46 |           value: value,
47 |         },
48 |       },
49 |       this.context.account ? {stripeAccount: this.context.account} : undefined
50 |     );
51 |   }
52 | 
53 |   async run(method: string, arg: any) {
54 |     const tool = this.tools.find((t) => t.method === method);
55 |     if (tool) {
56 |       const output = JSON.stringify(
57 |         await tool.execute(this.stripe, this.context, arg)
58 |       );
59 |       return output;
60 |     } else {
61 |       throw new Error('Invalid method ' + method);
62 |     }
63 |   }
64 | }
65 | 
66 | export default StripeAPI;
67 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/products/createProduct.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | export const createProductPrompt = (_context: Context = {}) => `
 6 | This tool will create a product in Stripe.
 7 | 
 8 | It takes two arguments:
 9 | - name (str): The name of the product.
10 | - description (str, optional): The description of the product.
11 | `;
12 | 
13 | export const createProduct = async (
14 |   stripe: Stripe,
15 |   context: Context,
16 |   params: z.infer<ReturnType<typeof createProductParameters>>
17 | ) => {
18 |   try {
19 |     const product = await stripe.products.create(
20 |       params,
21 |       context.account ? {stripeAccount: context.account} : undefined
22 |     );
23 | 
24 |     return product;
25 |   } catch (error) {
26 |     return 'Failed to create product';
27 |   }
28 | };
29 | 
30 | export const createProductParameters = (_context: Context = {}) =>
31 |   z.object({
32 |     name: z.string().describe('The name of the product.'),
33 |     description: z
34 |       .string()
35 |       .optional()
36 |       .describe('The description of the product.'),
37 |   });
38 | 
39 | export const createProductAnnotations = () => ({
40 |   destructiveHint: false,
41 |   idempotentHint: false,
42 |   openWorldHint: true,
43 |   readOnlyHint: false,
44 |   title: 'Create product',
45 | });
46 | 
47 | const tool = (context: Context): Tool => ({
48 |   method: 'create_product',
49 |   name: 'Create Product',
50 |   description: createProductPrompt(context),
51 |   parameters: createProductParameters(context),
52 |   annotations: createProductAnnotations(),
53 |   actions: {
54 |     products: {
55 |       create: true,
56 |     },
57 |   },
58 |   execute: createProduct,
59 | });
60 | 
61 | export default tool;
62 | 
```

--------------------------------------------------------------------------------
/python/tests/test_configuration.py:
--------------------------------------------------------------------------------

```python
 1 | import unittest
 2 | from stripe_agent_toolkit.configuration import is_tool_allowed
 3 | 
 4 | 
 5 | class TestConfigurations(unittest.TestCase):
 6 |     def test_allowed(self):
 7 |         tool = {
 8 |             "actions": {
 9 |                 "customers": {"create": True, "read": True},
10 |                 "invoices": {"create": True, "read": True},
11 |             }
12 |         }
13 | 
14 |         configuration = {
15 |             "actions": {
16 |                 "customers": {"create": True, "read": True},
17 |                 "invoices": {"create": True, "read": True},
18 |             }
19 |         }
20 | 
21 |         self.assertTrue(is_tool_allowed(tool, configuration))
22 | 
23 |     def test_partial_allowed(self):
24 |         tool = {
25 |             "actions": {
26 |                 "customers": {"create": True, "read": True},
27 |                 "invoices": {"create": True, "read": True},
28 |             }
29 |         }
30 | 
31 |         configuration = {
32 |             "actions": {
33 |                 "customers": {"create": True, "read": True},
34 |                 "invoices": {"create": True, "read": False},
35 |             }
36 |         }
37 | 
38 |         self.assertFalse(is_tool_allowed(tool, configuration))
39 | 
40 |     def test_not_allowed(self):
41 |         tool = {
42 |             "actions": {
43 |                 "payment_links": {"create": True},
44 |             }
45 |         }
46 | 
47 |         configuration = {
48 |             "actions": {
49 |                 "customers": {"create": True, "read": True},
50 |                 "invoices": {"create": True, "read": True},
51 |             }
52 |         }
53 | 
54 |         self.assertFalse(is_tool_allowed(tool, configuration))
55 | 
56 | 
57 | if __name__ == "__main__":
58 |     unittest.main()
59 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/customers/createCustomer.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const createCustomerPrompt = (_context: Context = {}) => `
 7 | This tool will create a customer in Stripe.
 8 | 
 9 | It takes two arguments:
10 | - name (str): The name of the customer.
11 | - email (str, optional): The email of the customer.
12 | `;
13 | 
14 | export const createCustomerParameters = (
15 |   _context: Context = {}
16 | ): z.AnyZodObject =>
17 |   z.object({
18 |     name: z.string().describe('The name of the customer'),
19 |     email: z.string().email().optional().describe('The email of the customer'),
20 |   });
21 | 
22 | export const createCustomerAnnotations = () => ({
23 |   destructiveHint: false,
24 |   idempotentHint: false,
25 |   openWorldHint: true,
26 |   readOnlyHint: false,
27 |   title: 'Create customer',
28 | });
29 | 
30 | export const createCustomer = async (
31 |   stripe: Stripe,
32 |   context: Context,
33 |   params: z.infer<ReturnType<typeof createCustomerParameters>>
34 | ) => {
35 |   try {
36 |     const customer = await stripe.customers.create(
37 |       params,
38 |       context.account ? {stripeAccount: context.account} : undefined
39 |     );
40 | 
41 |     return {id: customer.id};
42 |   } catch (error) {
43 |     return 'Failed to create customer';
44 |   }
45 | };
46 | 
47 | const tool = (context: Context): Tool => ({
48 |   method: 'create_customer',
49 |   name: 'Create Customer',
50 |   description: createCustomerPrompt(context),
51 |   parameters: createCustomerParameters(context),
52 |   annotations: createCustomerAnnotations(),
53 |   actions: {
54 |     customers: {
55 |       create: true,
56 |     },
57 |   },
58 |   execute: createCustomer,
59 | });
60 | 
61 | export default tool;
62 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/build-dxt.js:
--------------------------------------------------------------------------------

```javascript
 1 | /* eslint-disable no-sync */
 2 | const esbuild = require('esbuild');
 3 | const fsSync = require('fs');
 4 | 
 5 | const dxt = require('@anthropic-ai/dxt');
 6 | 
 7 | // Ensure dist directory exists
 8 | if (!fsSync.existsSync('dxt-dist')) {
 9 |   fsSync.mkdirSync('dxt-dist');
10 | }
11 | 
12 | // Build configuration
13 | const buildConfig = {
14 |   entryPoints: ['src/index.ts'],
15 |   bundle: true,
16 |   outfile: 'dxt-dist/index.js',
17 |   platform: 'node',
18 |   target: 'node18',
19 |   format: 'cjs',
20 |   external: [],
21 |   minify: true,
22 |   sourcemap: false,
23 |   metafile: false,
24 |   write: true,
25 |   logLevel: 'info',
26 | };
27 | 
28 | async function build() {
29 |   try {
30 |     console.log('🔨 Building with esbuild...');
31 | 
32 |     const result = await esbuild.build(buildConfig);
33 | 
34 |     if (result.errors.length > 0) {
35 |       console.error('❌ Build failed with errors:');
36 |       result.errors.forEach((error) => console.error(error));
37 |       throw new Error('Build failed with errors');
38 |     }
39 | 
40 |     if (result.warnings.length > 0) {
41 |       console.warn('⚠️  Build completed with warnings:');
42 |       result.warnings.forEach((warning) => console.warn(warning));
43 |     }
44 | 
45 |     // Make the output file executable
46 |     fsSync.chmodSync('dxt-dist/index.js', '755');
47 | 
48 |     console.log('✅ Build completed successfully!');
49 |     console.log('📦 Output: dxt-dist/index.js');
50 |   } catch (error) {
51 |     console.error('❌ Build failed:', error);
52 |     throw error;
53 |   }
54 | }
55 | 
56 | // Run the build
57 | build();
58 | 
59 | // Pack the actual DXT extension
60 | dxt.packExtension({
61 |   extensionPath: '.',
62 |   outputPath: 'stripe.dxt',
63 |   silent: true,
64 | });
65 | 
66 | console.log('✅ DXT extension built successfully!');
67 | console.log('📦 Output: stripe.dxt');
68 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/invoices/finalizeInvoice.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const finalizeInvoiceParameters = (
 7 |   _context: Context = {}
 8 | ): z.AnyZodObject =>
 9 |   z.object({
10 |     invoice: z.string().describe('The ID of the invoice to finalize.'),
11 |   });
12 | 
13 | export const finalizeInvoicePrompt = (_context: Context = {}) => `
14 | This tool will finalize an invoice in Stripe.
15 | 
16 | It takes one argument:
17 | - invoice (str): The ID of the invoice to finalize.
18 | `;
19 | 
20 | export const finalizeInvoice = async (
21 |   stripe: Stripe,
22 |   context: Context,
23 |   params: z.infer<ReturnType<typeof finalizeInvoiceParameters>>
24 | ) => {
25 |   try {
26 |     const invoice = await stripe.invoices.finalizeInvoice(
27 |       params.invoice,
28 |       context.account ? {stripeAccount: context.account} : undefined
29 |     );
30 | 
31 |     return {
32 |       id: invoice.id,
33 |       url: invoice.hosted_invoice_url,
34 |       customer: invoice.customer,
35 |       status: invoice.status,
36 |     };
37 |   } catch (error) {
38 |     return 'Failed to finalize invoice';
39 |   }
40 | };
41 | 
42 | export const finalizeInvoiceAnnotations = () => ({
43 |   destructiveHint: false,
44 |   idempotentHint: true,
45 |   openWorldHint: true,
46 |   readOnlyHint: false,
47 |   title: 'Finalize invoice',
48 | });
49 | 
50 | const tool = (context: Context): Tool => ({
51 |   method: 'finalize_invoice',
52 |   name: 'Finalize Invoice',
53 |   description: finalizeInvoicePrompt(context),
54 |   parameters: finalizeInvoiceParameters(context),
55 |   annotations: finalizeInvoiceAnnotations(),
56 |   actions: {
57 |     invoices: {
58 |       update: true,
59 |     },
60 |   },
61 |   execute: finalizeInvoice,
62 | });
63 | 
64 | export default tool;
65 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/products/listProducts.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const listProductsPrompt = (_context: Context = {}) => `
 7 | This tool will fetch a list of Products from Stripe.
 8 | 
 9 | It takes one optional argument:
10 | - limit (int, optional): The number of products to return.
11 | `;
12 | 
13 | export const listProducts = async (
14 |   stripe: Stripe,
15 |   context: Context,
16 |   params: z.infer<ReturnType<typeof listProductsParameters>>
17 | ) => {
18 |   try {
19 |     const products = await stripe.products.list(
20 |       params,
21 |       context.account ? {stripeAccount: context.account} : undefined
22 |     );
23 | 
24 |     return products.data;
25 |   } catch (error) {
26 |     return 'Failed to list products';
27 |   }
28 | };
29 | 
30 | export const listProductsParameters = (
31 |   _context: Context = {}
32 | ): z.AnyZodObject =>
33 |   z.object({
34 |     limit: z
35 |       .number()
36 |       .int()
37 |       .min(1)
38 |       .max(100)
39 |       .optional()
40 |       .describe(
41 |         'A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.'
42 |       ),
43 |   });
44 | 
45 | export const listProductsAnnotations = () => ({
46 |   destructiveHint: false,
47 |   idempotentHint: true,
48 |   openWorldHint: true,
49 |   readOnlyHint: true,
50 |   title: 'List products',
51 | });
52 | 
53 | const tool = (context: Context): Tool => ({
54 |   method: 'list_products',
55 |   name: 'List Products',
56 |   description: listProductsPrompt(context),
57 |   parameters: listProductsParameters(context),
58 |   annotations: listProductsAnnotations(),
59 |   actions: {
60 |     products: {
61 |       read: true,
62 |     },
63 |   },
64 |   execute: listProducts,
65 | });
66 | 
67 | export default tool;
68 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "@stripe/mcp",
 3 |   "version": "0.2.4",
 4 |   "homepage": "https://github.com/stripe/agent-toolkit/tree/main/modelcontextprotocol",
 5 |   "description": "A command line tool for setting up Stripe MCP server",
 6 |   "bin": "dist/index.js",
 7 |   "files": [
 8 |     "dist/index.js",
 9 |     "LICENSE",
10 |     "README.md",
11 |     "VERSION",
12 |     "package.json"
13 |   ],
14 |   "scripts": {
15 |     "build": "tsc && node -e \"require('fs').chmodSync('dist/index.js', '755')\"",
16 |     "clean": "rm -rf dist",
17 |     "lint": "eslint \"./**/*.ts*\"",
18 |     "prettier": "prettier './**/*.{js,ts,md,html,css}' --write",
19 |     "prettier-check": "prettier './**/*.{js,ts,md,html,css}' --check",
20 |     "test": "jest",
21 |     "build-dxt-extension": "node build-dxt.js"
22 |   },
23 |   "packageManager": "[email protected]",
24 |   "engines": {
25 |     "node": ">=18"
26 |   },
27 |   "dependencies": {
28 |     "@modelcontextprotocol/sdk": "^1.17.1",
29 |     "@stripe/agent-toolkit": "^0.7.11",
30 |     "colors": "^1.4.0"
31 |   },
32 |   "keywords": [
33 |     "mcp",
34 |     "modelcontextprotocol",
35 |     "stripe"
36 |   ],
37 |   "author": "Stripe <[email protected]> (https://stripe.com/)",
38 |   "license": "MIT",
39 |   "devDependencies": {
40 |     "@anthropic-ai/dxt": "^0.1.0",
41 |     "@eslint/compat": "^1.2.6",
42 |     "@types/jest": "^29.5.14",
43 |     "@types/node": "^22.13.4",
44 |     "@typescript-eslint/eslint-plugin": "^8.24.1",
45 |     "esbuild": "^0.25.5",
46 |     "eslint-config-prettier": "^10.0.1",
47 |     "eslint-plugin-import": "^2.31.0",
48 |     "eslint-plugin-jest": "^28.11.0",
49 |     "eslint-plugin-prettier": "^5.2.3",
50 |     "globals": "^15.15.0",
51 |     "jest": "^29.7.0",
52 |     "prettier": "^3.5.1",
53 |     "ts-jest": "^29.2.5",
54 |     "ts-node": "^10.9.2",
55 |     "typescript": "^5.8.3"
56 |   }
57 | }
58 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/configuration.py:
--------------------------------------------------------------------------------

```python
 1 | from typing import Literal, Optional
 2 | from typing_extensions import TypedDict
 3 | 
 4 | # Define Object type
 5 | Object = Literal[
 6 |     "customers",
 7 |     "invoices",
 8 |     "invoiceItems",
 9 |     "paymentLinks",
10 |     "products",
11 |     "prices",
12 |     "balance",
13 |     "refunds",
14 |     "paymentIntents",
15 | ]
16 | 
17 | 
18 | # Define Permission type
19 | class Permission(TypedDict, total=False):
20 |     create: Optional[bool]
21 |     update: Optional[bool]
22 |     read: Optional[bool]
23 | 
24 | 
25 | # Define BalancePermission type
26 | class BalancePermission(TypedDict, total=False):
27 |     read: Optional[bool]
28 | 
29 | 
30 | # Define Actions type
31 | class Actions(TypedDict, total=False):
32 |     customers: Optional[Permission]
33 |     invoices: Optional[Permission]
34 |     invoice_items: Optional[Permission]
35 |     payment_links: Optional[Permission]
36 |     products: Optional[Permission]
37 |     prices: Optional[Permission]
38 |     balance: Optional[BalancePermission]
39 |     refunds: Optional[Permission]
40 |     payment_intents: Optional[Permission]
41 |     billing_portal_sessions: Optional[Permission]
42 | 
43 | 
44 | # Define Context type
45 | class Context(TypedDict, total=False):
46 |     account: Optional[str]
47 | 
48 | 
49 | # Define Configuration type
50 | class Configuration(TypedDict, total=False):
51 |     actions: Optional[Actions]
52 |     context: Optional[Context]
53 | 
54 | 
55 | def is_tool_allowed(tool, configuration):
56 |     for resource, permissions in tool.get("actions", {}).items():
57 |         if resource not in configuration.get("actions", {}):
58 |             return False
59 |         for permission in permissions:
60 |             if (
61 |                 not configuration["actions"]
62 |                 .get(resource, {})
63 |                 .get(permission, False)
64 |             ):
65 |                 return False
66 |     return True
67 | 
```

--------------------------------------------------------------------------------
/typescript/src/cloudflare/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {z, ZodRawShape} from 'zod';
 2 | import {ToolCallback} from '@modelcontextprotocol/sdk/server/mcp.js';
 3 | import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';
 4 | import {registerPaidTool} from '../modelcontextprotocol/register-paid-tool';
 5 | import type {PaidToolOptions} from '../modelcontextprotocol/register-paid-tool';
 6 | 
 7 | // @ts-ignore: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'.
 8 | import {McpAgent} from 'agents/mcp';
 9 | 
10 | type Env = any;
11 | 
12 | type StripeState = {
13 |   customerId: string;
14 | };
15 | 
16 | export type PaymentState = {
17 |   stripe?: StripeState;
18 | };
19 | 
20 | export type PaymentProps = {
21 |   userEmail: string;
22 | };
23 | 
24 | // eslint-disable-next-line @typescript-eslint/naming-convention
25 | export abstract class experimental_PaidMcpAgent<
26 |   Bindings extends Env,
27 |   State extends PaymentState,
28 |   Props extends PaymentProps,
29 | > extends McpAgent<Bindings, State, Props> {
30 |   paidTool<Args extends ZodRawShape>(
31 |     toolName: string,
32 |     toolDescription: string,
33 |     paramsSchema: Args,
34 |     // @ts-ignore
35 |     paidCallback: ToolCallback<Args>,
36 |     options: Omit<PaidToolOptions, 'userEmail' | 'stripeSecretKey'>
37 |   ) {
38 |     const mcpServer: McpServer = this.server as unknown as McpServer;
39 | 
40 |     const userEmail = this.props.userEmail;
41 | 
42 |     const updatedOptions = {
43 |       ...options,
44 |       userEmail,
45 |       // @ts-ignore
46 |       stripeSecretKey: this.env.STRIPE_SECRET_KEY,
47 |     };
48 | 
49 |     // @ts-ignore
50 |     registerPaidTool(
51 |       mcpServer,
52 |       toolName,
53 |       toolDescription,
54 |       paramsSchema,
55 |       paidCallback,
56 |       updatedOptions
57 |     );
58 |   }
59 | }
60 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/subscriptions/cancelSubscription.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const cancelSubscription = async (
 7 |   stripe: Stripe,
 8 |   context: Context,
 9 |   params: z.infer<ReturnType<typeof cancelSubscriptionParameters>>
10 | ) => {
11 |   try {
12 |     const {subscription: subscriptionId, ...cancelParams} = params;
13 | 
14 |     const subscription = await stripe.subscriptions.cancel(
15 |       subscriptionId,
16 |       cancelParams,
17 |       context.account ? {stripeAccount: context.account} : undefined
18 |     );
19 | 
20 |     return subscription;
21 |   } catch (error) {
22 |     return 'Failed to cancel subscription';
23 |   }
24 | };
25 | 
26 | export const cancelSubscriptionParameters = (
27 |   _context: Context = {}
28 | ): z.AnyZodObject => {
29 |   return z.object({
30 |     subscription: z.string().describe('The ID of the subscription to cancel.'),
31 |   });
32 | };
33 | export const cancelSubscriptionPrompt = (_context: Context = {}): string => {
34 |   return `
35 | This tool will cancel a subscription in Stripe.
36 | 
37 | It takes the following arguments:
38 | - subscription (str, required): The ID of the subscription to cancel.
39 | `;
40 | };
41 | 
42 | export const cancelSubscriptionAnnotations = () => ({
43 |   destructiveHint: true,
44 |   idempotentHint: true,
45 |   openWorldHint: true,
46 |   readOnlyHint: false,
47 |   title: 'Cancel subscription',
48 | });
49 | 
50 | const tool = (context: Context): Tool => ({
51 |   method: 'cancel_subscription',
52 |   name: 'Cancel Subscription',
53 |   description: cancelSubscriptionPrompt(context),
54 |   parameters: cancelSubscriptionParameters(context),
55 |   annotations: cancelSubscriptionAnnotations(),
56 |   actions: {
57 |     subscriptions: {
58 |       update: true,
59 |     },
60 |   },
61 |   execute: cancelSubscription,
62 | });
63 | 
64 | export default tool;
65 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/coupons/listCoupons.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const listCouponsPrompt = (_context: Context = {}) => `
 7 | This tool will fetch a list of Coupons from Stripe.
 8 | 
 9 | It takes one optional argument:
10 | - limit (int, optional): The number of coupons to return.
11 | `;
12 | 
13 | export const listCouponsParameters = (_context: Context = {}) =>
14 |   z.object({
15 |     limit: z
16 |       .number()
17 |       .int()
18 |       .min(1)
19 |       .max(100)
20 |       .optional()
21 |       .describe(
22 |         'A limit on the number of objects to be returned. Limit can range between 1 and 100.'
23 |       ),
24 |   });
25 | 
26 | export const listCouponsAnnotations = () => ({
27 |   destructiveHint: false,
28 |   idempotentHint: true,
29 |   openWorldHint: true,
30 |   readOnlyHint: true,
31 |   title: 'List coupons',
32 | });
33 | 
34 | export const listCoupons = async (
35 |   stripe: Stripe,
36 |   context: Context,
37 |   params: z.infer<ReturnType<typeof listCouponsParameters>>
38 | ) => {
39 |   try {
40 |     const coupons = await stripe.coupons.list(
41 |       params,
42 |       context.account ? {stripeAccount: context.account} : undefined
43 |     );
44 | 
45 |     return coupons.data.map((coupon) => ({
46 |       id: coupon.id,
47 |       name: coupon.name,
48 |       percent_off: coupon.percent_off,
49 |       amount_off: coupon.amount_off,
50 |       duration: coupon.duration,
51 |     }));
52 |   } catch (error) {
53 |     return 'Failed to list coupons';
54 |   }
55 | };
56 | 
57 | const tool = (context: Context): Tool => ({
58 |   method: 'list_coupons',
59 |   name: 'List Coupons',
60 |   description: listCouponsPrompt(context),
61 |   parameters: listCouponsParameters(context),
62 |   annotations: listCouponsAnnotations(),
63 |   actions: {
64 |     coupons: {
65 |       read: true,
66 |     },
67 |   },
68 |   execute: listCoupons,
69 | });
70 | 
71 | export default tool;
72 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/prices/listPrices.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const listPrices = async (
 7 |   stripe: Stripe,
 8 |   context: Context,
 9 |   params: z.infer<ReturnType<typeof listPricesParameters>>
10 | ) => {
11 |   try {
12 |     const prices = await stripe.prices.list(
13 |       params,
14 |       context.account ? {stripeAccount: context.account} : undefined
15 |     );
16 | 
17 |     return prices.data;
18 |   } catch (error) {
19 |     return 'Failed to list prices';
20 |   }
21 | };
22 | 
23 | export const listPricesParameters = (_context: Context = {}): z.AnyZodObject =>
24 |   z.object({
25 |     product: z
26 |       .string()
27 |       .optional()
28 |       .describe('The ID of the product to list prices for.'),
29 |     limit: z
30 |       .number()
31 |       .int()
32 |       .min(1)
33 |       .max(100)
34 |       .optional()
35 |       .describe(
36 |         'A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.'
37 |       ),
38 |   });
39 | 
40 | export const listPricesAnnotations = () => ({
41 |   destructiveHint: false,
42 |   idempotentHint: true,
43 |   openWorldHint: true,
44 |   readOnlyHint: true,
45 |   title: 'List prices',
46 | });
47 | 
48 | export const listPricesPrompt = (_context: Context = {}) => `
49 | This tool will fetch a list of Prices from Stripe.
50 | 
51 | It takes two arguments.
52 | - product (str, optional): The ID of the product to list prices for.
53 | - limit (int, optional): The number of prices to return.
54 | `;
55 | 
56 | const tool = (context: Context): Tool => ({
57 |   method: 'list_prices',
58 |   name: 'List Prices',
59 |   description: listPricesPrompt(context),
60 |   parameters: listPricesParameters(context),
61 |   annotations: listPricesAnnotations(),
62 |   actions: {
63 |     prices: {
64 |       read: true,
65 |     },
66 |   },
67 |   execute: listPrices,
68 | });
69 | 
70 | export default tool;
71 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/refunds/functions.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createRefund} from '@/shared/refunds/createRefund';
 2 | 
 3 | const Stripe = jest.fn().mockImplementation(() => ({
 4 |   refunds: {
 5 |     create: jest.fn(),
 6 |   },
 7 | }));
 8 | 
 9 | let stripe: ReturnType<typeof Stripe>;
10 | 
11 | beforeEach(() => {
12 |   stripe = new Stripe('fake-api-key');
13 | });
14 | 
15 | describe('createRefund', () => {
16 |   it('should create a refund and return it', async () => {
17 |     const params = {
18 |       payment_intent: 'pi_123456',
19 |     };
20 | 
21 |     const mockRefund = {id: 're_123456'};
22 | 
23 |     const context = {};
24 | 
25 |     stripe.refunds.create.mockResolvedValue(mockRefund);
26 | 
27 |     const result = await createRefund(stripe, context, params);
28 | 
29 |     expect(stripe.refunds.create).toHaveBeenCalledWith(params, undefined);
30 |     expect(result).toEqual(mockRefund);
31 |   });
32 | 
33 |   it('should create a partial refund and return it', async () => {
34 |     const params = {
35 |       payment_intent: 'pi_123456',
36 |       amount: 500,
37 |     };
38 | 
39 |     const mockRefund = {id: 're_123456'};
40 | 
41 |     const context = {};
42 | 
43 |     stripe.refunds.create.mockResolvedValue(mockRefund);
44 | 
45 |     const result = await createRefund(stripe, context, params);
46 | 
47 |     expect(stripe.refunds.create).toHaveBeenCalledWith(params, undefined);
48 |     expect(result).toEqual(mockRefund);
49 |   });
50 | 
51 |   it('should specify the connected account if included in context', async () => {
52 |     const params = {
53 |       payment_intent: 'pi_123456',
54 |     };
55 | 
56 |     const mockRefund = {id: 're_123456'};
57 | 
58 |     const context = {
59 |       account: 'acct_123456',
60 |     };
61 | 
62 |     stripe.refunds.create.mockResolvedValue(mockRefund);
63 | 
64 |     const result = await createRefund(stripe, context, params);
65 | 
66 |     expect(stripe.refunds.create).toHaveBeenCalledWith(params, {
67 |       stripeAccount: context.account,
68 |     });
69 |     expect(result).toEqual(mockRefund);
70 |   });
71 | });
72 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/refunds/createRefund.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const createRefundPrompt = (_context: Context = {}) => `
 7 | This tool will refund a payment intent in Stripe.
 8 | 
 9 | It takes three arguments:
10 | - payment_intent (str): The ID of the payment intent to refund.
11 | - amount (int, optional): The amount to refund in cents.
12 | - reason (str, optional): The reason for the refund.
13 | `;
14 | 
15 | export const createRefund = async (
16 |   stripe: Stripe,
17 |   context: Context,
18 |   params: z.infer<ReturnType<typeof createRefundParameters>>
19 | ) => {
20 |   try {
21 |     const refund = await stripe.refunds.create(
22 |       params,
23 |       context.account ? {stripeAccount: context.account} : undefined
24 |     );
25 | 
26 |     return {
27 |       id: refund.id,
28 |       status: refund.status,
29 |       amount: refund.amount,
30 |     };
31 |   } catch (error) {
32 |     return 'Failed to create refund';
33 |   }
34 | };
35 | 
36 | export const createRefundParameters = (
37 |   _context: Context = {}
38 | ): z.AnyZodObject =>
39 |   z.object({
40 |     payment_intent: z
41 |       .string()
42 |       .describe('The ID of the PaymentIntent to refund.'),
43 |     amount: z
44 |       .number()
45 |       .int()
46 |       .optional()
47 |       .describe('The amount to refund in cents.'),
48 |   });
49 | 
50 | export const createRefundAnnotations = () => ({
51 |   destructiveHint: false,
52 |   idempotentHint: false,
53 |   openWorldHint: true,
54 |   readOnlyHint: false,
55 |   title: 'Create refund',
56 | });
57 | 
58 | const tool = (context: Context): Tool => ({
59 |   method: 'create_refund',
60 |   name: 'Create Refund',
61 |   description: createRefundPrompt(context),
62 |   parameters: createRefundParameters(context),
63 |   annotations: createRefundAnnotations(),
64 |   actions: {
65 |     refunds: {
66 |       create: true,
67 |     },
68 |   },
69 |   execute: createRefund,
70 | });
71 | 
72 | export default tool;
73 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/prices/createPrice.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const createPricePrompt = (_context: Context = {}) => `
 7 | This tool will create a price in Stripe. If a product has not already been specified, a product should be created first.
 8 | 
 9 | It takes three arguments:
10 | - product (str): The ID of the product to create the price for.
11 | - unit_amount (int): The unit amount of the price in cents.
12 | - currency (str): The currency of the price.
13 | `;
14 | 
15 | export const createPrice = async (
16 |   stripe: Stripe,
17 |   context: Context,
18 |   params: z.infer<ReturnType<typeof createPriceParameters>>
19 | ) => {
20 |   try {
21 |     const price = await stripe.prices.create(
22 |       params,
23 |       context.account ? {stripeAccount: context.account} : undefined
24 |     );
25 | 
26 |     return price;
27 |   } catch (error) {
28 |     return 'Failed to create price';
29 |   }
30 | };
31 | 
32 | export const createPriceParameters = (_context: Context = {}) =>
33 |   z.object({
34 |     product: z
35 |       .string()
36 |       .describe('The ID of the product to create the price for.'),
37 |     unit_amount: z
38 |       .number()
39 |       .int()
40 |       .describe('The unit amount of the price in cents.'),
41 |     currency: z.string().describe('The currency of the price.'),
42 |   });
43 | 
44 | export const createPriceAnnotations = () => ({
45 |   destructiveHint: false,
46 |   idempotentHint: false,
47 |   openWorldHint: true,
48 |   readOnlyHint: false,
49 |   title: 'Create price',
50 | });
51 | 
52 | const tool = (context: Context): Tool => ({
53 |   method: 'create_price',
54 |   name: 'Create Price',
55 |   description: createPricePrompt(context),
56 |   parameters: createPriceParameters(context),
57 |   annotations: createPriceAnnotations(),
58 |   actions: {
59 |     prices: {
60 |       create: true,
61 |     },
62 |   },
63 |   execute: createPrice,
64 | });
65 | 
66 | export default tool;
67 | 
```

--------------------------------------------------------------------------------
/python/stripe_agent_toolkit/strands/tool.py:
--------------------------------------------------------------------------------

```python
 1 | from strands.tools.tools import PythonAgentTool as StrandTool
 2 | import json
 3 | 
 4 | def StripeTool(api, tool) -> StrandTool:
 5 |     parameters = tool["args_schema"].model_json_schema()
 6 |     parameters["additionalProperties"] = False
 7 |     parameters["type"] = "object"
 8 | 
 9 |     def callback_wrapper(tool_input, **kwargs):
10 |         """Wrapper to handle additional parameters from strands framework."""
11 | 
12 |         # Extract toolUseId for the response
13 |         tool_use_id = None
14 |         if isinstance(tool_input, dict) and 'toolUseId' in tool_input:
15 |             tool_use_id = tool_input['toolUseId']
16 |             # Extract the actual parameters from the nested input structure
17 |             actual_params = tool_input.get('input', {})
18 |         elif isinstance(tool_input, str):
19 |             # Parse JSON string input
20 |             try:
21 |                 parsed = json.loads(tool_input)
22 |                 tool_use_id = parsed.get('toolUseId')
23 |                 actual_params = parsed.get('input', parsed)
24 |             except json.JSONDecodeError:
25 |                 actual_params = {}
26 |         elif isinstance(tool_input, dict):
27 |             actual_params = tool_input.copy()
28 |         else:
29 |             actual_params = {}
30 | 
31 |         # Call the Stripe API
32 |         result = api.run(tool["method"], **actual_params)
33 | 
34 |         # Return in the format expected by strands
35 |         response = {
36 |             "content": [{"text": result}]
37 |         }
38 | 
39 |         if tool_use_id:
40 |             response["toolUseId"] = tool_use_id
41 | 
42 |         return response
43 | 
44 |     return StrandTool(
45 |         tool_name=tool["method"],
46 |         tool_spec={
47 |             "name": tool["method"],
48 |             "description": tool["description"],
49 |             "inputSchema": {
50 |                 "json": parameters
51 |             }
52 |         },
53 |         callback=callback_wrapper
54 |     )
55 | 
```

--------------------------------------------------------------------------------
/modelcontextprotocol/manifest.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "dxt_version": "0.1",
 3 |   "name": "@stripe/mcp",
 4 |   "display_name": "Stripe",
 5 |   "version": "0.1.0",
 6 |   "description": "Manage resources in your Stripe account and search the Stripe knowledge base.",
 7 |   "author": {
 8 |     "name": "Stripe",
 9 |     "email": "[email protected]"
10 |   },
11 |   "documentation": "https://docs.stripe.com/mcp",
12 |   "user_config": {
13 |     "stripe_secret_key": {
14 |       "type": "string",
15 |       "title": "Stripe key",
16 |       "description": "Your Stripe API key. We recommend using a restricted access key.",
17 |       "multiple": false,
18 |       "required": true
19 |     }
20 |   },
21 |   "server": {
22 |     "type": "node",
23 |     "entry_point": "dxt-dist/index.js",
24 |     "mcp_config": {
25 |       "command": "node",
26 |       "args": ["${__dirname}/dxt-dist/index.js", "--tools=all"],
27 |       "env": {
28 |         "STRIPE_SECRET_KEY": "${user_config.stripe_secret_key}"
29 |       }
30 |     }
31 |   },
32 |   "tools": [
33 |     {"name": "search_documentation"},
34 |     {"name": "get_stripe_account_in"},
35 |     {"name": "create_customer"},
36 |     {"name": "list_customers"},
37 |     {"name": "create_product"},
38 |     {"name": "list_products"},
39 |     {"name": "create_price"},
40 |     {"name": "list_prices"},
41 |     {"name": "create_payment_link"},
42 |     {"name": "create_invoice"},
43 |     {"name": "list_invoices"},
44 |     {"name": "create_invoice_item"},
45 |     {"name": "finalize_invoice"},
46 |     {"name": "retrieve_balance"},
47 |     {"name": "create_refund"},
48 |     {"name": "list_payment_intents"},
49 |     {"name": "list_subscriptions"},
50 |     {"name": "cancel_subscription"},
51 |     {"name": "update_subscription"},
52 |     {"name": "list_coupons"},
53 |     {"name": "create_coupon"},
54 |     {"name": "update_dispute"},
55 |     {"name": "list_disputes"}
56 |   ],
57 |   "license": "MIT",
58 |   "repository": {
59 |     "type": "git",
60 |     "url": "https://github.com/stripe/agent-toolkit/tree/main"
61 |   },
62 |   "icon": "stripe_icon.png"
63 | }
64 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/configuration.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type {Tool} from './tools';
 2 | 
 3 | // Actions restrict the subset of API calls that can be made. They should
 4 | // be used in conjunction with Restricted API Keys. Setting a permission to false
 5 | // prevents the related "tool" from being considered.
 6 | export type Object =
 7 |   | 'customers'
 8 |   | 'disputes'
 9 |   | 'invoices'
10 |   | 'invoiceItems'
11 |   | 'paymentLinks'
12 |   | 'products'
13 |   | 'prices'
14 |   | 'balance'
15 |   | 'refunds'
16 |   | 'paymentIntents'
17 |   | 'subscriptions'
18 |   | 'documentation'
19 |   | 'coupons';
20 | 
21 | export type Permission = 'create' | 'update' | 'read';
22 | 
23 | export type Actions = {
24 |   [K in Object]?: {
25 |     [K in Permission]?: boolean;
26 |   };
27 | } & {
28 |   balance?: {
29 |     read?: boolean;
30 |   };
31 | };
32 | 
33 | // Context are settings that are applied to all requests made by the integration.
34 | export type Context = {
35 |   // Account is a Stripe Connected Account ID. If set, the integration will
36 |   // make requests for this Account.
37 |   account?: string;
38 | 
39 |   // Customer is a Stripe Customer ID. If set, the integration will
40 |   // make requests for this Customer.
41 |   customer?: string;
42 | 
43 |   // If set to 'modelcontextprotocol', the Stripe API calls will use a special
44 |   // header
45 |   mode?: 'modelcontextprotocol' | 'toolkit';
46 | };
47 | 
48 | // Configuration provides various settings and options for the integration
49 | // to tune and manage how it behaves.
50 | export type Configuration = {
51 |   actions?: Actions;
52 |   context?: Context;
53 | };
54 | 
55 | export const isToolAllowed = (
56 |   tool: Tool,
57 |   configuration: Configuration
58 | ): boolean => {
59 |   return Object.keys(tool.actions).every((resource) => {
60 |     // For each resource.permission pair, check the configuration.
61 |     // @ts-ignore
62 |     const permissions = tool.actions[resource];
63 | 
64 |     return Object.keys(permissions).every((permission) => {
65 |       // @ts-ignore
66 |       return configuration.actions[resource]?.[permission] === true;
67 |     });
68 |   });
69 | };
70 | 
```

--------------------------------------------------------------------------------
/typescript/src/openai/toolkit.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import StripeAPI from '../shared/api';
 2 | import tools from '../shared/tools';
 3 | import {isToolAllowed, type Configuration} from '../shared/configuration';
 4 | import {zodToJsonSchema} from 'zod-to-json-schema';
 5 | import type {
 6 |   ChatCompletionTool,
 7 |   ChatCompletionMessageToolCall,
 8 |   ChatCompletionToolMessageParam,
 9 | } from 'openai/resources';
10 | 
11 | class StripeAgentToolkit {
12 |   private _stripe: StripeAPI;
13 | 
14 |   tools: ChatCompletionTool[];
15 | 
16 |   constructor({
17 |     secretKey,
18 |     configuration,
19 |   }: {
20 |     secretKey: string;
21 |     configuration: Configuration;
22 |   }) {
23 |     this._stripe = new StripeAPI(secretKey, configuration.context);
24 | 
25 |     const context = configuration.context || {};
26 |     const filteredTools = tools(context).filter((tool) =>
27 |       isToolAllowed(tool, configuration)
28 |     );
29 | 
30 |     this.tools = filteredTools.map((tool) => ({
31 |       type: 'function',
32 |       function: {
33 |         name: tool.method,
34 |         description: tool.description,
35 |         parameters: zodToJsonSchema(tool.parameters),
36 |       },
37 |     }));
38 |   }
39 | 
40 |   getTools(): ChatCompletionTool[] {
41 |     return this.tools;
42 |   }
43 | 
44 |   /**
45 |    * Processes a single OpenAI tool call by executing the requested function.
46 |    *
47 |    * @param {ChatCompletionMessageToolCall} toolCall - The tool call object from OpenAI containing
48 |    *   function name, arguments, and ID.
49 |    * @returns {Promise<ChatCompletionToolMessageParam>} A promise that resolves to a tool message
50 |    *   object containing the result of the tool execution with the proper format for the OpenAI API.
51 |    */
52 |   async handleToolCall(toolCall: ChatCompletionMessageToolCall) {
53 |     const args = JSON.parse(toolCall.function.arguments);
54 |     const response = await this._stripe.run(toolCall.function.name, args);
55 |     return {
56 |       role: 'tool',
57 |       tool_call_id: toolCall.id,
58 |       content: response,
59 |     } as ChatCompletionToolMessageParam;
60 |   }
61 | }
62 | 
63 | export default StripeAgentToolkit;
64 | 
```

--------------------------------------------------------------------------------
/typescript/src/shared/customers/listCustomers.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import Stripe from 'stripe';
 2 | import {z} from 'zod';
 3 | import type {Context} from '@/shared/configuration';
 4 | import type {Tool} from '@/shared/tools';
 5 | 
 6 | export const listCustomersPrompt = (_context: Context = {}) => `
 7 | This tool will fetch a list of Customers from Stripe.
 8 | 
 9 | It takes two arguments:
10 | - limit (int, optional): The number of customers to return.
11 | - email (str, optional): A case-sensitive filter on the list based on the customer's email field.
12 | `;
13 | 
14 | export const listCustomersParameters = (_context: Context = {}) =>
15 |   z.object({
16 |     limit: z
17 |       .number()
18 |       .int()
19 |       .min(1)
20 |       .max(100)
21 |       .optional()
22 |       .describe(
23 |         'A limit on the number of objects to be returned. Limit can range between 1 and 100.'
24 |       ),
25 |     email: z
26 |       .string()
27 |       .optional()
28 |       .describe(
29 |         "A case-sensitive filter on the list based on the customer's email field. The value must be a string."
30 |       ),
31 |   });
32 | 
33 | export const listCustomersAnnotations = () => ({
34 |   destructiveHint: false,
35 |   idempotentHint: true,
36 |   openWorldHint: true,
37 |   readOnlyHint: true,
38 |   title: 'List customers',
39 | });
40 | 
41 | export const listCustomers = async (
42 |   stripe: Stripe,
43 |   context: Context,
44 |   params: z.infer<ReturnType<typeof listCustomersParameters>>
45 | ) => {
46 |   try {
47 |     const customers = await stripe.customers.list(
48 |       params,
49 |       context.account ? {stripeAccount: context.account} : undefined
50 |     );
51 | 
52 |     return customers.data.map((customer) => ({id: customer.id}));
53 |   } catch (error) {
54 |     return 'Failed to list customers';
55 |   }
56 | };
57 | 
58 | const tool = (context: Context): Tool => ({
59 |   method: 'list_customers',
60 |   name: 'List Customers',
61 |   description: listCustomersPrompt(context),
62 |   parameters: listCustomersParameters(context),
63 |   annotations: listCustomersAnnotations(),
64 |   actions: {
65 |     customers: {
66 |       read: true,
67 |     },
68 |   },
69 |   execute: listCustomers,
70 | });
71 | 
72 | export default tool;
73 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/subscriptions/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {listSubscriptionsParameters} from '@/shared/subscriptions/listSubscriptions';
 2 | import {cancelSubscriptionParameters} from '@/shared/subscriptions/cancelSubscription';
 3 | import {updateSubscriptionParameters} from '@/shared/subscriptions/updateSubscription';
 4 | 
 5 | describe('listSubscriptionsParameters', () => {
 6 |   it('should return the correct parameters if no context', () => {
 7 |     const parameters = listSubscriptionsParameters({});
 8 | 
 9 |     const fields = Object.keys(parameters.shape);
10 |     expect(fields).toEqual(['customer', 'price', 'status', 'limit']);
11 |     expect(fields.length).toBe(4);
12 |   });
13 | 
14 |   it('should return the correct parameters if customer is specified', () => {
15 |     const parameters = listSubscriptionsParameters({customer: 'cus_123'});
16 | 
17 |     const fields = Object.keys(parameters.shape);
18 |     expect(fields).toEqual(['price', 'status', 'limit']);
19 |     expect(fields.length).toBe(3);
20 |   });
21 | });
22 | 
23 | describe('cancelSubscriptionParameters', () => {
24 |   it('should return the correct parameters', () => {
25 |     const parameters = cancelSubscriptionParameters({});
26 |     const fields = Object.keys(parameters.shape);
27 |     expect(fields).toEqual(['subscription']);
28 |   });
29 | });
30 | 
31 | describe('updateSubscriptionParameters', () => {
32 |   it('should return the correct parameters', () => {
33 |     const parameters = updateSubscriptionParameters({});
34 |     const fields = Object.keys(parameters.shape);
35 |     expect(fields).toEqual(['subscription', 'proration_behavior', 'items']);
36 |   });
37 | 
38 |   it('should have the required subscription parameter', () => {
39 |     const parameters = updateSubscriptionParameters({});
40 |     expect(parameters.shape.subscription).toBeDefined();
41 |   });
42 | 
43 |   it('should have the optional parameters defined', () => {
44 |     const parameters = updateSubscriptionParameters({});
45 |     expect(parameters.shape.proration_behavior).toBeDefined();
46 |     expect(parameters.shape.items).toBeDefined();
47 |   });
48 | });
49 | 
```

--------------------------------------------------------------------------------
/typescript/src/test/shared/invoices/parameters.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import {createInvoiceParameters} from '@/shared/invoices/createInvoice';
 2 | import {listInvoicesParameters} from '@/shared/invoices/listInvoices';
 3 | import {finalizeInvoiceParameters} from '@/shared/invoices/finalizeInvoice';
 4 | 
 5 | describe('createInvoiceParameters', () => {
 6 |   it('should return the correct parameters if no context', () => {
 7 |     const parameters = createInvoiceParameters({});
 8 | 
 9 |     const fields = Object.keys(parameters.shape);
10 |     expect(fields).toEqual(['customer', 'days_until_due']);
11 |     expect(fields.length).toBe(2);
12 |   });
13 | 
14 |   it('should return the correct parameters if customer is specified', () => {
15 |     const parameters = createInvoiceParameters({customer: 'cus_123'});
16 | 
17 |     const fields = Object.keys(parameters.shape);
18 |     expect(fields).toEqual(['days_until_due']);
19 |     expect(fields.length).toBe(1);
20 |   });
21 | });
22 | 
23 | describe('listInvoicesParameters', () => {
24 |   it('should return the correct parameters if no context', () => {
25 |     const parameters = listInvoicesParameters({});
26 | 
27 |     const fields = Object.keys(parameters.shape);
28 |     expect(fields).toEqual(['customer', 'limit']);
29 |     expect(fields.length).toBe(2);
30 |   });
31 | 
32 |   it('should return the correct parameters if customer is specified', () => {
33 |     const parameters = listInvoicesParameters({customer: 'cus_123'});
34 | 
35 |     const fields = Object.keys(parameters.shape);
36 |     expect(fields).toEqual(['limit']);
37 |     expect(fields.length).toBe(1);
38 |   });
39 | });
40 | 
41 | describe('finalizeInvoiceParameters', () => {
42 |   it('should return the correct parameters if no context', () => {
43 |     const parameters = finalizeInvoiceParameters({});
44 | 
45 |     const fields = Object.keys(parameters.shape);
46 |     expect(fields).toEqual(['invoice']);
47 |     expect(fields.length).toBe(1);
48 |   });
49 | 
50 |   it('should return the correct parameters if customer is specified', () => {
51 |     const parameters = finalizeInvoiceParameters({customer: 'cus_123'});
52 | 
53 |     const fields = Object.keys(parameters.shape);
54 |     expect(fields).toEqual(['invoice']);
55 |     expect(fields.length).toBe(1);
56 |   });
57 | });
58 | 
```
Page 1/4FirstPrevNextLast