#
tokens: 49870/50000 162/256 files (page 1/5)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 5. Use http://codebase.md/stripe/agent-toolkit?page={x} to view the full context.

# Directory Structure

```
├── .github
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   └── feature_request.yml
│   └── workflows
│       ├── main.yml
│       ├── npm_release_shared.yml
│       ├── pypi_release.yml
│       └── sync-skills.yml
├── .gitignore
├── .vscode
│   ├── extensions.json
│   ├── launch.json
│   └── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── gemini-extension.json
├── LICENSE
├── llm
│   ├── ai-sdk
│   │   ├── jest.config.ts
│   │   ├── LICENSE
│   │   ├── meter
│   │   │   ├── examples
│   │   │   │   ├── .env.example
│   │   │   │   ├── .gitignore
│   │   │   │   ├── anthropic.ts
│   │   │   │   ├── google.ts
│   │   │   │   ├── openai.ts
│   │   │   │   ├── README.md
│   │   │   │   └── tsconfig.json
│   │   │   ├── index.ts
│   │   │   ├── meter-event-logging.ts
│   │   │   ├── meter-event-types.ts
│   │   │   ├── README.md
│   │   │   ├── tests
│   │   │   │   ├── ai-sdk-billing-wrapper-anthropic.test.ts
│   │   │   │   ├── ai-sdk-billing-wrapper-general.test.ts
│   │   │   │   ├── ai-sdk-billing-wrapper-google.test.ts
│   │   │   │   ├── ai-sdk-billing-wrapper-openai.test.ts
│   │   │   │   ├── ai-sdk-billing-wrapper-other-providers.test.ts
│   │   │   │   ├── meter-event-logging.test.ts
│   │   │   │   └── model-name-normalization.test.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── types.ts
│   │   │   ├── utils.ts
│   │   │   └── wrapperV2.ts
│   │   ├── package.json
│   │   ├── pnpm-lock.yaml
│   │   ├── provider
│   │   │   ├── examples
│   │   │   │   ├── .env.example
│   │   │   │   ├── .gitignore
│   │   │   │   ├── anthropic.ts
│   │   │   │   ├── google.ts
│   │   │   │   ├── openai.ts
│   │   │   │   ├── README.md
│   │   │   │   └── tsconfig.json
│   │   │   ├── index.ts
│   │   │   ├── README.md
│   │   │   ├── stripe-language-model.ts
│   │   │   ├── stripe-provider.ts
│   │   │   ├── tests
│   │   │   │   ├── stripe-language-model.test.ts
│   │   │   │   ├── stripe-provider.test.ts
│   │   │   │   └── utils.test.ts
│   │   │   ├── tsconfig.build.json
│   │   │   ├── tsconfig.json
│   │   │   ├── types.ts
│   │   │   └── utils.ts
│   │   ├── README.md
│   │   ├── tsconfig.json
│   │   └── tsup.config.ts
│   ├── README.md
│   └── token-meter
│       ├── examples
│       │   ├── anthropic.ts
│       │   ├── gemini.ts
│       │   └── openai.ts
│       ├── index.ts
│       ├── jest.config.ts
│       ├── LICENSE
│       ├── meter-event-logging.ts
│       ├── meter-event-types.ts
│       ├── package.json
│       ├── pnpm-lock.yaml
│       ├── README.md
│       ├── tests
│       │   ├── meter-event-logging.test.ts
│       │   ├── model-name-normalization.test.ts
│       │   ├── token-meter-anthropic.test.ts
│       │   ├── token-meter-gemini.test.ts
│       │   ├── token-meter-general.test.ts
│       │   ├── token-meter-openai.test.ts
│       │   └── type-detection.test.ts
│       ├── token-meter.ts
│       ├── tsconfig.build.json
│       ├── tsconfig.json
│       ├── types.ts
│       └── utils
│           └── type-detection.ts
├── README.md
├── SECURITY.md
├── skills
│   ├── get-started-kiro.md
│   ├── README.md
│   ├── stripe-best-practices.md
│   └── sync.js
└── tools
    ├── modelcontextprotocol
    │   ├── .dxtignore
    │   ├── .gitignore
    │   ├── .node-version
    │   ├── .prettierrc
    │   ├── build-dxt.js
    │   ├── Dockerfile
    │   ├── eslint.config.mjs
    │   ├── jest.config.ts
    │   ├── LICENSE
    │   ├── manifest.json
    │   ├── package.json
    │   ├── pnpm-lock.yaml
    │   ├── README.md
    │   ├── server.json
    │   ├── 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
    └── 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
        ├── LICENSE
        ├── 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

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

```
22.14.0

```

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

```
dist/
node_modules/
*.dxt
dxt-dist/
```

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

```
OPENAI_API_KEY=""
STRIPE_SECRET_KEY=""
```

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

```
OPENAI_API_KEY=""
STRIPE_SECRET_KEY=""
```

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

```
# wrangler project
.dev.vars
.wrangler/

```

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

```
LANGSMITH_API_KEY=""
STRIPE_SECRET_KEY=""

```

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

```
node_modules/
node_modules/**/*.*
tsconfig.json
Dockerfile
```

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

```
OPENAI_API_KEY=""
STRIPE_SECRET_KEY=""
STRIPE_CUSTOMER_ID=""
STRIPE_METER=""

```

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

```
{
  "singleQuote": true,
  "trailingComma": "es5",
  "bracketSpacing": false
}

```

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

```
{
  "singleQuote": true,
  "trailingComma": "es5",
  "bracketSpacing": false
}

```

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

```
STRIPE_SECRET_KEY=""
OPENAI_API_BASE=""
OPENAI_MODEL_NAME="gpt-4o"
OPENAI_API_KEY=""

```

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

```
STRIPE_SECRET_KEY=""
STRIPE_CUSTOMER_ID=""
STRIPE_METER_INPUT=""
STRIPE_METER_OUTPUT=""

```

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

```
LANGSMITH_API_KEY=""
STRIPE_SECRET_KEY=""
OPENAI_API_BASE=""
OPENAI_MODEL_NAME="gpt-4o"
OPENAI_API_KEY=""

```

--------------------------------------------------------------------------------
/llm/ai-sdk/provider/examples/.env.example:
--------------------------------------------------------------------------------

```
STRIPE_API_KEY=sk_test_...
STRIPE_CUSTOMER_ID=cus_...
OPENAI_API_KEY=...
ANTHROPIC_API_KEY=...
GOOGLE_GENERATIVE_AI_API_KEY=...

```

--------------------------------------------------------------------------------
/llm/ai-sdk/meter/examples/.gitignore:
--------------------------------------------------------------------------------

```
# Environment variables
.env
.env.local
.env.*.local

# Allow .env.example
!.env.example

# Node modules (if any get installed here)
node_modules/

# Build outputs
dist/

```

--------------------------------------------------------------------------------
/llm/ai-sdk/provider/examples/.gitignore:
--------------------------------------------------------------------------------

```
# Environment variables
.env
.env.local
.env.*.local

# Allow .env.example
!.env.example

# Node modules (if any get installed here)
node_modules/

# Build outputs
dist/


```

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

```
STRIPE_SECRET_KEY=sk_test_......
STRIPE_PRICE_ID_ONE_TIME_PAYMENT=price_1RJJwjR1b4cWtS0UCIDTSU3V
STRIPE_PRICE_ID_SUBSCRIPTION=price_1RJJwjR1bGyW9S0UCIDTSU3V
STRIPE_PRICE_ID_USAGE_BASED_SUBSCRIPTION=price_1RJdGWR1bGyW9S0UucbYBFBZ
```

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

```
; https://editorconfig.org/

root = true

[*]
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8

[*.{cfg,ini,json,toml,yml}]
indent_size = 2

[Makefile]
indent_style = tab

```

--------------------------------------------------------------------------------
/llm/ai-sdk/meter/examples/.env.example:
--------------------------------------------------------------------------------

```
# Stripe API Configuration
# Copy this file to .env and fill in your actual values

# Your Stripe API key (test or live)
# Get it from: https://dashboard.stripe.com/apikeys
STRIPE_API_KEY=sk_test_...

# Your Stripe Customer ID
# Format: cus_xxxxx
STRIPE_CUSTOMER_ID=cus_...

# Provider-specific API keys
# (Only required for the provider you want to test)

# OpenAI API key
OPENAI_API_KEY=sk-...

# Anthropic API key
ANTHROPIC_API_KEY=sk-ant-...

# Google Generative AI API key
GOOGLE_GENERATIVE_AI_API_KEY=...


```

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

```
OPENAI_API_KEY=your_openai_api_key
STRIPE_SECRET_KEY=your_stripe_secret_key

# Your email address and app password
# https://support.google.com/accounts/answer/185833?hl=en
[email protected]
EMAIL_PASSWORD=your_app_specific_password
# Only respond to emails send to this address (defaults to $EMAIL_ADDRESS)
SUPPORT_ADDRESS="[email protected]"

# If your connecting to gmail, you don't need to customize these
IMAP_SERVER=imap.gmail.com
IMAP_PORT=993
SMTP_SERVER=smtp.gmail.com
SMTP_PORT=587

```

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

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

```

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

```
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/
junk/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp
.cache

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

.turbo


/cloudflare/
/openai/
/ai-sdk/
/langchain/
/modelcontextprotocol/
```

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

```
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Node modules
node_modules/
junk/

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
#   For a library or package, you might want to ignore these files since the code is
#   intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# poetry
#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
#   This is especially recommended for binary packages to ensure reproducibility, and is more
#   commonly ignored for libraries.
#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
#   in version control.
#   https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
#  and can be added to the global gitignore or merged into this file.  For a more nuclear
#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

```

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

```markdown
# CrewAI Example

## Setup

Copy the `.env.template` and populate with your values.

```
cp .env.template .env
```

## Usage

```
python main.py
```

```

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

```markdown
# LangChain Example

## Setup

Copy the `.env.template` and populate with your values.

```
cp .env.template .env
```

## Usage

```
python main.py
```

```

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

```markdown
# AI SDK Example

## Setup

Copy the `.env.template` and populate with your values.

```
cp .env.template .env
```

## Usage

```
npx ts-node index.ts --env
```

```

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

```markdown
# OpenAI Example

## Setup

Copy the `.env.template` and populate with your values.

```
cp .env.template .env
```

## Usage

```
npx ts-node index.ts --env
```

```

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

```markdown
# LangChain Example

## Setup

Copy the `.env.template` and populate with your values.

```
cp .env.template .env
```

## Usage

```
npx ts-node index.ts --env
```

```

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

```markdown
# Skills

Agents need instructions to follow. The better the instructions, the more likely the agent will be able to do something useful for/with their user.

Stripe has:

- LLM readable Docs (append .md to the end of any Docs)
- `search_stripe_documentation` tool built into our MCP server
- MCP Prompts

This folder is a folder of "prompts" synced with prompts on mcp.stripe.com. The syncing is done through a GitHub action.

```

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

```markdown
# Web Search Example

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.

## Setup

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.

2. Copy `.env.template` to `.env` populate with the relevant values.

```bash
OPENAI_API_KEY=your_openai_api_key
OPENAI_VECTOR_STORE_ID=your_openai_vector_store_id
STRIPE_SECRET_KEY=your_stripe_secret_key
```

## Usage

```bash
python main.py
```

You can see the invoices created in the Stripe Dashboard.

```

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

```markdown
# Web Search Example

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.

## Setup

1. Create a Stripe Billing Meter and Stripe Customer following the [Stripe documentation](https://docs.stripe.com/billing/subscriptions/usage-based/implementation-guide).

2. Copy `.env.template` to `.env` populate with the relevant values.

```bash
OPENAI_API_KEY=your_openai_api_key
STRIPE_SECRET_KEY=your_stripe_secret_key
STRIPE_CUSTOMER_ID=your_stripe_customer_id
STRIPE_METER=your_stripe_meter
```

## Usage

```bash
python main.py
```

You can see the usage in the Stripe Dashboard.

```

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

```markdown
# MCP Payments

A simple MCP server helper to require payment to use tools, whether subscription or usage-based.

This implementation works on Vercel with a standard MCP server.

## Usage Instructions for `registerPaidTool`

1. Import the `registerPaidTool` function from this package.
2. Call `registerPaidTool` with your MCP server, tool name, description, params schema, callback, and payment options.
3. Example usage:

```ts
import {registerPaidTool} from './register-paid-tool';
import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';

const server = new McpServer({
  name: 'mcp-typescript server',
  version: '0.1.0',
});

registerPaidTool(
  server,
  'add_numbers',
  {
    a: z.number(),
    b: z.number(),
  },
  ({a, b}) => {
    return {
      content: [{type: 'text', text: `Result: ${a + b}`}],
    };
  },
  {
    priceId: '{{PRICE_ID}}',
    successUrl: '{{CALLBACK_URL}}',
    email: '{{EMAIL}}',
    paymentReason:
      'You must pay a subscription to add two big numbers together.',
    stripeSecretKey: '{{SECRET_KEY}}',
  }
);
```

```

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

```markdown
# PaidMcpAgent

An example of how to monetize an MCP server with Stripe.

## Setup

1. Copy `.dev.vars.example` to `.dev.vars` and add your Stripe API key.
2. Configure the required Stripe environment variables:
   - `STRIPE_SECRET_KEY`: Your Stripe secret key
   - `STRIPE_ONETIME_SUBSCRIPTION_PRICE_ID`: Price ID for one-time payment
   - `STRIPE_PRICE_ID_USAGE_BASED_SUBSCRIPTION`: Price ID for usage-based subscription
   - `STRIPE_METER_EVENT_NAME`: Event name for usage metering
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.

## Development

```
pnpm i
pnpm dev
```

## Testing

Open up the inspector and connect to your MCP server.

```
npx @modelcontextprotocol/inspector@latest http://localhost:4242/sse
```

### Deploy

```
npx wrangler secret put STRIPE_SECRET_KEY
npx wrangler secret put STRIPE_PRICE_ID_ONE_TIME_PAYMENT
npx wrangler secret put STRIPE_ONETIME_SUBSCRIPTION_PRICE_ID
npx wrangler secret put STRIPE_PRICE_ID_USAGE_BASED_SUBSCRIPTION
```

### Feedback

Please leave feedback throught the GitHub issues and discussions on how you
would use the `PaidMcpAgent`!

```

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

```markdown
# Email Support Agent

Sample app to help you automate your email support. Powered by OpenAI's Agent SDK and [Stripe Agent Toolkit](https://github.com/stripe/ai).

Customize this agent to fit your own needs by cloning and modifying [support_agent.py](./support_agent.py).

## Features

The support agent currently can:

- Answer FAQ questions
- Update billing information through Customer Portal
- Send any missing invoices

We also support a REPL to help you test your agent without sending a gazillion emails.

## How it Works

The support agent will:

- Connects to your email using an IMAP client
- Checks for unread emails every 30 seconds
- Generates and sends a reply
- Marks the emails as read

If it doesn't know how to answer the question, it will not respond and ignore the email.

## Setup

1. Install uv (if not already installed):

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

2. Clone this repository
3. Create and activate a virtual environment:

```bash
uv venv
source .venv/bin/activate  # On Unix/macOS
# or
.venv\Scripts\activate  # On Windows
```

4. Install dependencies:

```bash
uv sync
```

5. Copy `.env.example` to `.env`:

```bash
cp .env.example .env
```

6. Configure your `.env` file with:
   - Email credentials (create an [app-specific password](https://support.google.com/accounts/answer/185833) for Gmail)
   - IMAP/SMTP server details (defaults for Gmail provided in .env.example)
   - OpenAI API key
   - Stripe Secret Key

## Usage

Run the agent:

```bash
python main.py
```

Run the REPL with:

```bash
python repl.py
```

## Customize for your App

This repository is just a sample app tailored to our [example website](http://standupjack.com).

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.

```

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

```markdown
# MCP Payments

`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/).

## Usage

### Setup

```
npm install @stripe/agent-toolkit
```

Modify your existing MCP server by extending with `PaidMcpAgent` instead of `McpAgent`.

```ts
import {
  PaymentState,
  experimental_PaidMcpAgent as PaidMcpAgent,
} from '@stripe/agent-toolkit/cloudflare';

type Props = {
  userEmail: string;
};

type State = PaymentState & {};

export class MyMCP extends PaidMcpAgent<Bindings, State, Props> {}
```

Lastly, set your `STRIPE_SECRET_KEY` in `.dev.vars` to test, and then `npx wrangler secret put STRIPE_SECRET_KEY` when ready for production.

### Monetizing a tool

Consider a basic tool that can add two numbers together:

```ts
this.server.tool('add', {a: z.number(), b: z.number()}, ({a, b}) => {
  return {
    content: [{type: 'text', text: `Result: ${a + b}`}],
  };
});
```

To make this paid using a subscription, first create a product and price in the Stripe Dashboard.

Then, replace `this.server.tool` with `this.paidTool` and add your payment config: `priceId`, `paymentReason`, and `successUrl`.

```ts
this.paidTool(
  'add_numbers',
  {
    a: z.number(),
    b: z.number(),
  },
  ({a, b}) => {
    return {
      content: [{type: 'text', text: `Result: ${a + b}`}],
    };
  },
  {
    priceId: '{{PRICE_ID}}',
    successUrl: 'https://mcp.mysite.com/success',
    paymentReason:
      'You must pay a subscription to add two big numbers together.',
  }
);
```

## Authentication

`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.

```

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

```markdown
# Stripe Agent Toolkit - Python

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
library is not exhaustive of the entire Stripe API. It is built directly on top
of the [Stripe Python SDK][python-sdk].

## Installation

You don't need this source code unless you want to modify the package. If you just
want to use the package, just run:

```sh
uv pip install stripe-agent-toolkit
```

### Requirements

-   Python 3.11+

## Usage

The library needs to be configured with your account's secret key which is
available in your [Stripe Dashboard][api-keys].

```python
from stripe_agent_toolkit.openai.toolkit import StripeAgentToolkit

stripe_agent_toolkit = StripeAgentToolkit(
    secret_key="sk_test_...",
    configuration={
        "actions": {
            "payment_links": {
                "create": True,
            },
        }
    },
)
```

The toolkit works with OpenAI's Agent SDK, LangChain, and CrewAI and can be passed as a list of tools. For example:

```python
from agents import Agent

stripe_agent = Agent(
    name="Stripe Agent",
    instructions="You are an expert at integrating with Stripe",
    tools=stripe_agent_toolkit.get_tools()
)
```

Examples for OpenAI's Agent SDK,LangChain, and CrewAI are included in [/examples](/examples).

[python-sdk]: https://github.com/stripe/stripe-python
[api-keys]: https://dashboard.stripe.com/account/apikeys

#### Context

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).

```python
stripe_agent_toolkit = StripeAgentToolkit(
    secret_key="sk_test_...",
    configuration={
        "context": {
            "account": "acct_123"
        }
    }
)
```

## Development

```
uv venv --python 3.11
source .venv/bin/activate
uv pip install -r requirements.txt
```

```

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

```markdown
# LLM metering packages

This directory contains two packages for tracking and billing LLM token usage with Stripe.

## Private preview access required

Stripe Billing for LLM Tokens is currently only available to organizations participating in the Billing for LLM Tokens Private Preview. If you don't have access and would like to request it, please visit:

**[Request Access to Billing for LLM Tokens Private Preview](https://docs.stripe.com/billing/token-billing)**

## Packages

### `@stripe/ai-sdk`

The Stripe AI SDK provides tools for integrating AI models with Stripe's billing infrastructure when using the Vercel AI SDK. It includes two components:



- **Provider** (`@stripe/ai-sdk/provider`): A custom Vercel AI SDK provider that routes requests through Stripe's LLM proxy at `llm.stripe.com`. It provides a unified interface to access OpenAI, Google Gemini, and Anthropic Claude models with automatic usage tracking and billing integration.

- **Meter** (`@stripe/ai-sdk/meter`): A wrapper utility that adds billing tracking to any Vercel AI SDK v2 language model. This allows you to use your preferred provider while still tracking usage in Stripe without changing your existing provider setup.

### Use ai-sdk when

- You're using or want to use Vercel AI SDK
- You want a unified interface across multiple AI providers
- You want AI SDK-specific features like tool calling abstractions
- You prefer the AI SDK's streaming abstractions


[View ai-sdk documentation](./ai-sdk/README.md)

### `@stripe/token-meter`

@stripe/token-meter provides generic token metering for native AI SDKs with automatic Stripe billing integration. Unlike the ai-sdk package, this works directly with native SDKs from OpenAI, Anthropic, and Google Gemini without requiring the Vercel AI SDK or any other framework.

It automatically detects provider and response types, supports both streaming and non-streaming responses, and sends billing events asynchronously to Stripe without blocking your application.

### Use token-meter when

- You're using native SDKs (OpenAI, Anthropic, Google) directly
- You don't want framework dependencies
- You need maximum control over API parameters
- You're working with embeddings or specialized APIs

[View token-meter documentation](./token-meter/README.md)


## Installation

For Vercel AI SDK integration:
```bash
npm install @stripe/ai-sdk
```

For native SDK integration:
```bash
npm install @stripe/token-meter
```

## Additional resources

- [Stripe Meter Events Documentation](https://docs.stripe.com/api/billing/meter-event)
- [Stripe Token Billing Documentation](https://docs.stripe.com/billing/token-billing)
- [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)

## License

MIT


```

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

```markdown
# Stripe Model Context Protocol

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.

## Setup

Stripe hosts a remote MCP server at https://mcp.stripe.com. View the docs [here](https://docs.stripe.com/mcp).

## Local

To run the Stripe MCP server locally using npx, use the following command:

```bash
# To set up all available tools
npx -y @stripe/mcp --tools=all --api-key=YOUR_STRIPE_SECRET_KEY

# To set up specific tools
npx -y @stripe/mcp --tools=customers.create,customers.read,products.create --api-key=YOUR_STRIPE_SECRET_KEY

# To configure a Stripe connected account
npx -y @stripe/mcp --tools=all --api-key=YOUR_STRIPE_SECRET_KEY --stripe-account=CONNECTED_ACCOUNT_ID
```

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.

### Usage with Claude Desktop

Add the following to your `claude_desktop_config.json`. See [here](https://modelcontextprotocol.io/quickstart/user) for more details.

```
{
  "mcpServers": {
    "stripe": {
      "command": "npx",
      "args": [
          "-y",
          "@stripe/mcp",
          "--tools=all",
          "--api-key=STRIPE_SECRET_KEY"
      ]
    }
  }
}
```

of if you're using Docker

```
{
    “mcpServers”: {
        “stripe”: {
            “command”: “docker",
            “args”: [
                “run”,
                "--rm",
                "-i",
                “mcp/stripe”,
                “--tools=all”,
                “--api-key=STRIPE_SECRET_KEY”
            ]
        }
    }
}

```

### Usage with Gemini CLI

1. Install [Gemini CLI](https://google-gemini.github.io/gemini-cli/#-installation) through your preferred method.
2. Install the Stripe MCP extension: `gemini extensions install https://github.com/stripe/ai`.
3. Start Gemini CLI: `gemini`.
4. Go through the OAUTH flow: `/mcp auth stripe`.

## Available tools

See the [Stripe MCP documentation](https://docs.stripe.com/mcp#tools) for a list of tools.

## Debugging the Server

To debug your server, you can use the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector).

First build the server

```
npm run build
```

Run the following command in your terminal:

```bash
# Start MCP Inspector and server with all tools
npx @modelcontextprotocol/inspector node dist/index.js --tools=all --api-key=YOUR_STRIPE_SECRET_KEY
```

### Build using Docker

First build the server

```
docker build -t mcp/stripe .
```

Run the following command in your terminal:

```bash
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

```

### Instructions

1. Replace `YOUR_STRIPE_SECRET_KEY` with your actual Stripe API secret key.
2. Run the command to start the MCP Inspector.
3. Open the MCP Inspector UI in your browser and click Connect to start the MCP server.
4. You can see the list of tools you selected and test each tool individually.

```

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

```markdown
# Stripe Agent Toolkit - TypeScript

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.

## Installation

You don't need this source code unless you want to modify the package. If you just
want to use the package run:

```
npm install @stripe/agent-toolkit
```

### Requirements

- Node 18+

## Usage

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.

```typescript
import {StripeAgentToolkit} from '@stripe/agent-toolkit/langchain';

const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    actions: {
      paymentLinks: {
        create: true,
      },
    },
  },
});
```

### Tools

The toolkit works with LangChain and Vercel's AI SDK and can be passed as a list of tools. For example:

```typescript
import {AgentExecutor, createStructuredChatAgent} from 'langchain/agents';

const tools = stripeAgentToolkit.getTools();

const agent = await createStructuredChatAgent({
  llm,
  tools,
  prompt,
});

const agentExecutor = new AgentExecutor({
  agent,
  tools,
});
```

#### Context

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).

```typescript
const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    context: {
      account: 'acct_123',
    },
  },
});
```

### Metered billing

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.

```typescript
import {StripeAgentToolkit} from '@stripe/agent-toolkit/ai-sdk';
import {openai} from '@ai-sdk/openai';
import {
  generateText,
  experimental_wrapLanguageModel as wrapLanguageModel,
} from 'ai';

const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    actions: {
      paymentLinks: {
        create: true,
      },
    },
  },
});

const model = wrapLanguageModel({
  model: openai('gpt-4o'),
  middleware: stripeAgentToolkit.middleware({
    billing: {
      customer: 'cus_123',
      meters: {
        input: 'input_tokens',
        output: 'output_tokens',
      },
    },
  }),
});
```

This works with both `generateText` and `generateStream` from the Vercel AI SDK.

## Model Context Protocol

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.

```typescript
import {StripeAgentToolkit} from '@stripe/agent-toolkit/modelcontextprotocol';
import {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js';

const server = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    actions: {
      paymentLinks: {
        create: true,
      },
      products: {
        create: true,
      },
      prices: {
        create: true,
      },
    },
  },
});

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error('Stripe MCP Server running on stdio');
}

main().catch((error) => {
  console.error('Fatal error in main():', error);
  process.exit(1);
});
```

[node-sdk]: https://github.com/stripe/stripe-node
[api-keys]: https://dashboard.stripe.com/account/apikeys

```

--------------------------------------------------------------------------------
/llm/ai-sdk/meter/examples/README.md:
--------------------------------------------------------------------------------

```markdown
# AI SDK Billing Wrapper Examples

This directory contains examples demonstrating how to use the AI SDK Billing Wrapper to automatically track and report token usage to Stripe for billing purposes when using the Vercel AI SDK.

## Overview

The AI SDK Billing Wrapper intercepts calls to language models and automatically sends usage data to Stripe's meter events API, enabling you to bill customers based on their AI token consumption without manually tracking usage.

## Setup

1. Install dependencies from the ai-sdk-billing-wrapper directory:

```bash
cd llm/ai-sdk-billing-wrapper
npm install
```

2. Set up environment variables in the examples directory:

```bash
cd examples
cp .env.example .env
```

Then edit `.env` and add your credentials:

```bash
# Required for all examples
STRIPE_API_KEY=sk_test_...
STRIPE_CUSTOMER_ID=cus_...

# Provider-specific (only required for the provider you want to test)
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_GENERATIVE_AI_API_KEY=...
```

## Running examples

Run examples from the examples directory using ts-node:

### OpenAI examples

```bash
npx ts-node openai.ts
```

Demonstrates:
- Basic text generation
- Streaming responses
- System messages
- Multi-turn conversations
- Different GPT models (GPT-4o-mini, GPT-4)
- Max tokens configuration

### Anthropic Claude examples

```bash
npx ts-node anthropic.ts
```

Demonstrates:
- Basic text generation with Claude Sonnet
- Streaming responses
- System messages
- Multi-turn conversations
- Claude Haiku for faster responses
- Max tokens configuration

### Google Gemini examples

```bash
npx ts-node google.ts
```

Demonstrates:
- Basic text generation with Gemini
- Streaming with Gemini Flash
- System messages
- Multi-turn conversations
- Temperature control

## How it works

The `meteredModel` wrapper automatically:

1. **Intercepts API Calls**: Wraps any AI SDK v2 language model
2. **Tracks Token Usage**: Captures input tokens, output tokens, and model information
3. **Reports to Stripe**: Sends meter events to Stripe after each generation
4. **Handles Streaming**: Works with both streaming and non-streaming responses

## Basic usage pattern

```typescript
import { meteredModel } from '@stripe/ai-sdk-billing-wrapper';
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';

const model = meteredModel(
  openai('gpt-4o-mini'),
  process.env.STRIPE_API_KEY,
  'cus_xxxxx'
);

const { text } = await generateText({
  model,
  prompt: 'Hello!',
});
```

## Supported providers

The wrapper works with any AI SDK provider that implements the v2 specification (`LanguageModelV2`):

**Supported:**
- OpenAI (`@ai-sdk/openai`)
- Anthropic Claude (`@ai-sdk/anthropic`)
- Google Gemini (`@ai-sdk/google`)
- Azure OpenAI (via `@ai-sdk/openai`)
- Amazon Bedrock (`@ai-sdk/amazon-bedrock`)
- Together AI (via `createOpenAI`)
- Any custom provider implementing `LanguageModelV2`

**Not supported:**
- Groq (`@ai-sdk/groq`) - uses v1 specification
- Any provider using `LanguageModelV1`

The wrapper enforces v2-only models at TypeScript compile time.

## Stripe meter events

Each API call generates meter events sent to Stripe:

```javascript
{
  event_name: 'token-billing-tokens',
  payload: {
    stripe_customer_id: 'cus_xxxxx',
    value: '100',
    model: 'openai/gpt-4o-mini',
    token_type: 'input'
  }
}
```

Metadata included:
- Provider (e.g., "openai", "anthropic", "google")
- Model ID (e.g., "gpt-4o-mini", "claude-sonnet-4")
- Input tokens
- Output tokens

## Error handling

The wrapper handles errors gracefully:

- **Invalid Customer ID**: Throws an error before making the API call
- **Unsupported Models**: TypeScript prevents usage at compile time
- **Stripe API Errors**: Logged but don't interrupt the AI generation
- **Missing Tokens**: Handles responses without usage information

## Additional resources

- [Stripe Meter Events Documentation](https://docs.stripe.com/api/billing/meter-event)
- [Stripe Token Billing Documentation](https://docs.stripe.com/billing/token-billing)
- [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)
- [AI SDK Providers](https://sdk.vercel.ai/docs/providers)

```

--------------------------------------------------------------------------------
/llm/ai-sdk/provider/examples/README.md:
--------------------------------------------------------------------------------

```markdown
# Stripe AI SDK Provider Examples

This directory contains examples demonstrating how to use the Stripe AI SDK Provider to interact with various LLM models through Stripe's `llm.stripe.com` proxy.

## Overview

The Stripe AI SDK Provider is a custom provider for the Vercel AI SDK that routes all requests through Stripe's LLM proxy, automatically tracking token usage for billing purposes.

## Setup

1. Install dependencies (from the ai-sdk-provider directory):
```bash
cd llm/ai-sdk-provider
npm install
```

2. **Set up environment variables** in the examples directory:
```bash
cd examples
cp .env.example .env
```

Then edit `.env` and add your credentials:
```bash
# Required: Your Stripe API key
STRIPE_API_KEY=sk_test_...

# Required: Your Stripe Customer ID
STRIPE_CUSTOMER_ID=cus_...
```

## Running examples

Each example file demonstrates different use cases. Run them from the examples directory:

### OpenAI models
```bash
cd examples
npx ts-node openai.ts
```

Examples include:
- Simple text generation
- Streaming responses
- Multi-turn conversations
- Reasoning models (o3)
- Tool calling

### Google Gemini models
```bash
npx ts-node google.ts
```

Examples include:
- Text generation with Gemini 2.5 Pro
- Streaming with Gemini Flash
- Using Gemini Lite models
- Custom headers

### Anthropic Claude models
```bash
npx ts-node anthropic.ts
```

Examples include:
- Simple text generation
- Streaming with Claude Opus
- Claude Sonnet and Haiku models
- Tool calling
- Per-call customer ID override

## Supported models

### OpenAI
- `openai/gpt-5`
- `openai/gpt-5-mini`
- `openai/gpt-5-nano`
- `openai/gpt-4.1`
- `openai/gpt-4.1-mini`
- `openai/gpt-4.1-nano`
- `openai/gpt-4o`
- `openai/gpt-4o-mini`
- `openai/o3`, `openai/o3-mini`, `openai/o3-pro`
- `openai/o1`, `openai/o1-mini`, `openai/o1-pro`

### Google Gemini
- `google/gemini-2.5-pro`
- `google/gemini-2.5-flash`
- `google/gemini-2.5-flash-lite`
- `google/gemini-2.0-flash`
- `google/gemini-2.0-flash-lite`

### Anthropic Claude
- `anthropic/claude-opus-4-1`
- `anthropic/claude-opus-4`
- `anthropic/claude-sonnet-4`
- `anthropic/claude-3-7-sonnet`
- `anthropic/claude-3-5-haiku`
- `anthropic/claude-3-haiku`

## Usage patterns

### Basic setup

```typescript
import { createStripe } from '@stripe/ai-sdk/provider';
import { generateText } from 'ai';

const stripeLLM = createStripe({
  apiKey: process.env.STRIPE_API_KEY!,
  customerId: process.env.STRIPE_CUSTOMER_ID, // Optional default
});

const model = stripe('openai/gpt-5');
```

### Customer ID options

You can specify the customer ID in three ways (in order of priority):

1. **Per-call override** (highest priority):
```typescript
await generateText({
  model: stripe('openai/gpt-5'),
  prompt: 'Hello!',
  providerOptions: {
    stripe: {
      customerId: 'cus_override'
    }
  }
});
```

2. **Model-level setting**:
```typescript
const model = stripe('openai/gpt-5', {
  customerId: 'cus_model_level'
});
```

3. **Provider-level default**:
```typescript
const stripeLLM = createStripe({
  apiKey: '...',
  customerId: 'cus_default'
});
```

### Streaming

```typescript
import { streamText } from 'ai';

const result = await streamText({
  model: stripe('google/gemini-2.5-flash'),
  prompt: 'Tell me a story',
});

for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}
```

### Tool calling

```typescript
const result = await generateText({
  model: stripe('anthropic/claude-sonnet-4'),
  prompt: 'What is the weather?',
  tools: {
    getWeather: {
      description: 'Get weather for a location',
      parameters: {
        type: 'object',
        properties: {
          location: { type: 'string' }
        },
        required: ['location']
      },
      execute: async ({ location }) => {
        return { temperature: 72, condition: 'Sunny' };
      }
    }
  }
});
```

## How it works

1. All requests are routed to `https://llm.stripe.com/chat/completions`
2. Your Stripe API key is included as the `Authorization` header
3. The customer ID is included as the `X-Stripe-Customer-ID` header
4. Stripe automatically tracks token usage and bills the customer according to your Token Billing configuration

## Learn more

- [Stripe Token Billing Documentation](https://stripe.com/docs)
- [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)
- [AI SDK Provider Specification](https://github.com/vercel/ai/tree/main/packages/provider)


```

--------------------------------------------------------------------------------
/llm/ai-sdk/README.md:
--------------------------------------------------------------------------------

```markdown
# Stripe AI SDK - Provider and metering utilities for Vercel AI SDK

The Stripe AI SDK provides comprehensive tools for integrating AI models with Stripe's billing infrastructure. This unified package includes both a custom Vercel AI SDK provider and metering utilities for tracking token usage across any AI SDK provider.

## Private preview access required

The Stripe AI SDK is currently only available to organizations participating in the Billing for LLM Tokens Private Preview. If you do not have access and would like to request it, please visit:

**[Request Access to Billing for LLM Tokens Private Preview](https://docs.stripe.com/billing/token-billing)**

## Overview

This package contains two main components:

### **Provider** (`@stripe/ai-sdk/provider`)

A custom Vercel AI SDK provider that routes requests through Stripe's LLM proxy at `llm.stripe.com`, enabling automatic usage tracking and billing integration.

**Key Features:**
- **Unified API**: Access OpenAI, Google Gemini, and Anthropic Claude through a single interface
- **Automatic tracking**: Token usage is automatically reported to Stripe
- **Built-in billing**: Seamlessly integrate AI costs into your Stripe billing workflow
- **Customer attribution**: Automatically attribute usage to specific customers

**Quick Start:**
```typescript
import { createStripe } from '@stripe/ai-sdk/provider';
import { generateText } from 'ai';

const stripeLLM = createStripe({
  apiKey: process.env.STRIPE_API_KEY,
  customerId: 'cus_xxxxx',
});

const { text } = await generateText({
  model: stripe('openai/gpt-5'),
  prompt: 'What are the three primary colors?',
});
```

[→ Full Provider Documentation](./provider/README.md)

### **Meter** (`@stripe/ai-sdk/meter`)

A wrapper utility that adds billing tracking to any Vercel AI SDK language model, allowing you to use your preferred provider while still tracking usage in Stripe.

**Key Features:**
- **Universal Compatibility**: Works with any AI SDK v2 provider
- **Non-Intrusive**: Preserves all original model functionality
- **Fire-and-Forget**: Billing events are sent asynchronously
- **Automatic Metering**: Token consumption is automatically tracked
- **Customer Attribution**: Attribute usage to specific customers

**Quick Start:**
```typescript
import { meteredModel } from '@stripe/ai-sdk/meter';
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';

const model = meteredModel(
  openai('gpt-4o-mini'),
  process.env.STRIPE_API_KEY,
  'cus_xxxxx'
);

const { text } = await generateText({
  model,
  prompt: 'What are the three primary colors?',
});
```

[→ Full Meter Documentation](./meter/README.md)

## Installation

```bash
npm install @stripe/ai-sdk
```

## Which should I use?

### Use the **Provider** when:
- You want a unified interface to multiple AI providers
- You prefer routing through Stripe's LLM proxy
- You want automatic usage tracking without any wrapper code
- You're building a new application

### Use the **Meter** when:
- You need to use specific provider features or configurations
- You want to keep your existing provider setup
- You need direct access to the native provider APIs
- You're integrating into an existing codebase

## Usage examples

### Provider example

```typescript
import { createStripe } from '@stripe/ai-sdk/provider';
import { streamText } from 'ai';

const stripeLLM = createStripe({
  apiKey: process.env.STRIPE_API_KEY,
  customerId: 'cus_xxxxx',
});

// Works with any supported model
const result = await streamText({
  model: stripeLLM('anthropic/claude-sonnet-4'),
  prompt: 'Write a short story about AI.',
});

for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}
```

### Meter example

```typescript
import { meteredModel } from '@stripe/ai-sdk/meter';
import { anthropic } from '@ai-sdk/anthropic';
import { streamText } from 'ai';

const model = meteredModel(
  anthropic('claude-3-5-sonnet-20241022'),
  process.env.STRIPE_API_KEY,
  'cus_xxxxx'
);

const result = await streamText({
  model,
  prompt: 'Write a short story about AI.',
});

for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}
```

## Supported models

### Provider models
The provider supports models from:
- **OpenAI**: GPT-5, GPT-4.1, o3, o1, and more
- **Google**: Gemini 2.5 Pro, Gemini 2.5 Flash, and more
- **Anthropic**: Claude Opus 4, Claude Sonnet 4, Claude Haiku, and more

### Meter compatibility
The meter works with any AI SDK v2 provider, including:
- OpenAI (`@ai-sdk/openai`)
- Anthropic (`@ai-sdk/anthropic`)
- Google Gemini (`@ai-sdk/google`)
- Azure OpenAI
- Amazon Bedrock
- And any custom v2 provider

## Token usage tracking

Both components automatically report token usage to Stripe meter events:

```javascript
{
  event_name: 'token-billing-tokens',
  payload: {
    stripe_customer_id: 'cus_xxxxx',
    value: '100',
    model: 'openai/gpt-4o-mini',
    token_type: 'input'
  }
}
```

## Documentation

- [Provider Documentation](./provider/README.md)
- [Meter Documentation](./meter/README.md)
- [Stripe Token Billing Documentation](https://docs.stripe.com/billing/token-billing)
- [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)

## Examples

- [Provider Examples](./provider/examples/)
- [Meter Examples](./meter/examples/)

## License

MIT


```

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

```markdown
![Hero GIF](https://stripe.dev/images/badges/ai-banner.gif)

# Stripe AI

This repo is the one-stop shop for building AI-powered products and businesses on top of Stripe. 

It contains a collection of SDKs to help you integrate Stripe with LLMs and agent frameworks, including: 

* [`@stripe/agent-toolkit`](/tools/typescript) - for integrating Stripe APIs with popular agent frameworks through function calling—available in [Python](/tools/python) and [TypeScript](/tools/typescript).
* [`@stripe/ai-sdk`](/llm/ai-sdk) - for integrating Stripe's billing infrastructure with Vercel's [`ai`](https://npm.im/ai) and [`@ai-sdk`](https://ai-sdk.dev/) libraries.
* [`@stripe/token-meter`](/llm/token-meter) - for integrating Stripe's billing infrastructure with native SDKs from OpenAI, Anthropic, and Google Gemini, without any framework dependencies.

## Model Context Protocol (MCP)

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).

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:

```sh
npx -y @stripe/mcp --tools=all --api-key=YOUR_STRIPE_SECRET_KEY
```

See [MCP](/tools/modelcontextprotocol) for more details.

## Agent toolkit

Stripe's Agent Toolkit enables popular agent frameworks including OpenAI's Agent SDK, LangChain, CrewAI, and Vercel's AI SDK to integrate with Stripe APIs through function calling. The library is not exhaustive of the entire Stripe API. It includes support for Python and TypeScript, and is built directly on top of the Stripe [Python][python-sdk] and [Node][node-sdk] SDKs.

Included below are basic instructions, but refer to [Python](/tools/python) and [TypeScript](/tools/typescript) packages for more information.

### Python

#### Installation

You don't need this source code unless you want to modify the package. If you just
want to use the package run:

```sh
pip install stripe-agent-toolkit
```

##### Requirements

- Python 3.11+

#### Usage

The library needs to be configured with your account's secret key which is
available in your [Stripe Dashboard][api-keys].

```python
from stripe_agent_toolkit.openai.toolkit import StripeAgentToolkit

stripe_agent_toolkit = StripeAgentToolkit(
    secret_key="sk_test_...",
    configuration={
        "actions": {
            "payment_links": {
                "create": True,
            },
        }
    },
)
```

The toolkit works with OpenAI's Agent SDK, LangChain, and CrewAI and can be passed as a list of tools. For example:

```python
from agents import Agent

stripe_agent = Agent(
    name="Stripe Agent",
    instructions="You are an expert at integrating with Stripe",
    tools=stripe_agent_toolkit.get_tools()
)
```

Examples for OpenAI's Agent SDK,LangChain, and CrewAI are included in [/examples](/tools/python/examples).

##### Context

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).

```python
stripe_agent_toolkit = StripeAgentToolkit(
    secret_key="sk_test_...",
    configuration={
        "context": {
            "account": "acct_123"
        }
    }
)
```

### TypeScript

#### Installation

You don't need this source code unless you want to modify the package. If you just
want to use the package run:

```sh
npm install @stripe/agent-toolkit
```

##### Requirements

- Node 18+

#### Usage

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.

```typescript
import { StripeAgentToolkit } from "@stripe/agent-toolkit/langchain";

const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    actions: {
      paymentLinks: {
        create: true,
      },
    },
  },
});
```

##### Tools

The toolkit works with LangChain and Vercel's AI SDK and can be passed as a list of tools. For example:

```typescript
import { AgentExecutor, createStructuredChatAgent } from "langchain/agents";

const tools = stripeAgentToolkit.getTools();

const agent = await createStructuredChatAgent({
  llm,
  tools,
  prompt,
});

const agentExecutor = new AgentExecutor({
  agent,
  tools,
});
```

##### Context

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).

```typescript
const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    context: {
      account: "acct_123",
    },
  },
});
```

## Supported API methods

See the [Stripe MCP](https://docs.stripe.com/mcp) docs for a list of supported methods.

[python-sdk]: https://github.com/stripe/stripe-python
[node-sdk]: https://github.com/stripe/stripe-node
[api-keys]: https://dashboard.stripe.com/account/apikeys

## License

[MIT](LICENSE)
```

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

```markdown
# Tools

## Model Context Protocol

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).

It can also be used to create autonomous agents.

For a local MCP, see the [MCP](/modelcontextprotocol) package.

## Agent Toolkit

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
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.

Included below are basic instructions, but refer to [Python](/tools/python), [TypeScript](/tools/typescript) packages for more information.

## Model Context Protocol

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:

```bash
npx -y @stripe/mcp --tools=all --api-key=YOUR_STRIPE_SECRET_KEY
```

## Python

### Installation

You don't need this source code unless you want to modify the package. If you just
want to use the package run:

```sh
pip install stripe-agent-toolkit
```

#### Requirements

- Python 3.11+

### Usage

The library needs to be configured with your account's secret key which is
available in your [Stripe Dashboard][api-keys].

```python
from stripe_agent_toolkit.openai.toolkit import StripeAgentToolkit

stripe_agent_toolkit = StripeAgentToolkit(
    secret_key="sk_test_...",
    configuration={
        "actions": {
            "payment_links": {
                "create": True,
            },
        }
    },
)
```

The toolkit works with OpenAI's Agent SDK, LangChain, and CrewAI and can be passed as a list of tools. For example:

```python
from agents import Agent

stripe_agent = Agent(
    name="Stripe Agent",
    instructions="You are an expert at integrating with Stripe",
    tools=stripe_agent_toolkit.get_tools()
)
```

Examples for OpenAI's Agent SDK,LangChain, and CrewAI are included in [/examples](/tools/python/examples).

#### Context

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).

```python
stripe_agent_toolkit = StripeAgentToolkit(
    secret_key="sk_test_...",
    configuration={
        "context": {
            "account": "acct_123"
        }
    }
)
```

## TypeScript

### Installation

You don't need this source code unless you want to modify the package. If you just
want to use the package run:

```
npm install @stripe/agent-toolkit
```

#### Requirements

- Node 18+

### Usage

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.

```typescript
import { StripeAgentToolkit } from "@stripe/agent-toolkit/langchain";

const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    actions: {
      paymentLinks: {
        create: true,
      },
    },
  },
});
```

#### Tools

The toolkit works with LangChain and Vercel's AI SDK and can be passed as a list of tools. For example:

```typescript
import { AgentExecutor, createStructuredChatAgent } from "langchain/agents";

const tools = stripeAgentToolkit.getTools();

const agent = await createStructuredChatAgent({
  llm,
  tools,
  prompt,
});

const agentExecutor = new AgentExecutor({
  agent,
  tools,
});
```

#### Context

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).

```typescript
const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    context: {
      account: "acct_123",
    },
  },
});
```

#### Metered billing

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.

```typescript
import { StripeAgentToolkit } from "@stripe/agent-toolkit/ai-sdk";
import { openai } from "@ai-sdk/openai";
import {
  generateText,
  experimental_wrapLanguageModel as wrapLanguageModel,
} from "ai";

const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    actions: {
      paymentLinks: {
        create: true,
      },
    },
  },
});

const model = wrapLanguageModel({
  model: openai("gpt-4o"),
  middleware: stripeAgentToolkit.middleware({
    billing: {
      customer: "cus_123",
      meters: {
        input: "input_tokens",
        output: "output_tokens",
      },
    },
  }),
});
```

## Supported API methods

See the [Stripe MCP](https://docs.stripe.com/mcp) docs for a list of supported methods.

[python-sdk]: https://github.com/stripe/stripe-python
[node-sdk]: https://github.com/stripe/stripe-node
[api-keys]: https://dashboard.stripe.com/account/apikeys

```

--------------------------------------------------------------------------------
/llm/ai-sdk/meter/README.md:
--------------------------------------------------------------------------------

```markdown
# Metering utilities for Vercel AI SDK

The Stripe AI SDK Meter enables automatic token usage tracking and billing for any Vercel AI SDK language model. This wrapper intercepts AI SDK calls and automatically reports usage to Stripe meter events, making it easy to bill customers for their AI consumption.

> This is part of the [`@stripe/ai-sdk`](../README.md) package. See the main README for an overview of all available tools.

## Private preview access required

The Stripe AI SDK is currently only available to organizations participating in the Billing for LLM Tokens Private Preview. If you don't have access and would like to request it, please visit:

**[Request Access to Billing for LLM Tokens Private Preview](https://docs.stripe.com/billing/token-billing)**

## Why use the AI SDK Meter?

- **Universal Compatibility**: Works with any AI SDK v2 provider (OpenAI, Anthropic, Google, and more)
- **Automatic Usage Tracking**: Token consumption is automatically tracked and reported to Stripe
- **Seamless Integration**: Simple wrapper function requires minimal code changes
- **Customer Attribution**: Automatically attribute usage to specific customers for accurate billing
- **Non-Intrusive**: Preserves all original model functionality while adding billing capabilities
- **Fire-and-Forget**: Billing events are sent asynchronously without blocking API responses

Learn more about Stripe's Token Billing and request access to the latest features from the [Stripe Documentation](https://docs.stripe.com/billing/token-billing).

## Installation

```bash
npm install @stripe/ai-sdk
```

## Basic usage

Wrap any AI SDK v2 language model with `meteredModel` to enable automatic usage tracking:

```typescript
import { meteredModel } from '@stripe/ai-sdk/meter';
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';

const model = meteredModel(
  openai('gpt-4o-mini'),
  process.env.STRIPE_API_KEY,
  'cus_xxxxx'
);

const { text } = await generateText({
  model,
  prompt: 'What are the three primary colors?',
});
```

## API reference

### `meteredModel(model, stripeApiKey, stripeCustomerId)`

Wraps a Vercel AI SDK language model to automatically report usage to Stripe meter events.

**Parameters:**
- `model` (LanguageModelV2): The AI SDK language model instance to wrap
- `stripeApiKey` (string): Your Stripe API key
- `stripeCustomerId` (string): The Stripe customer ID to attribute usage to

**Returns:**
The wrapped model with identical functionality plus automatic usage tracking.

## Supported providers

The wrapper works with any AI SDK provider that implements the v2 specification (`LanguageModelV2`):

**Example supported providers:**
- OpenAI (`@ai-sdk/openai`)
- Anthropic (`@ai-sdk/anthropic`)
- Google Gemini (`@ai-sdk/google`)
- Azure OpenAI (via `@ai-sdk/openai`)
- Amazon Bedrock (`@ai-sdk/amazon-bedrock`)
- Any custom provider implementing `LanguageModelV2`

## Examples

### Streaming responses

```typescript
import { meteredModel } from '@stripe/ai-sdk/meter';
import { anthropic } from '@ai-sdk/anthropic';
import { streamText } from 'ai';

const model = meteredModel(
  anthropic('claude-3-5-sonnet-20241022'),
  process.env.STRIPE_API_KEY,
  'cus_xxxxx'
);

const result = streamText({
  model,
  prompt: 'Write a short story about AI.',
});

for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}
```

### Multi-turn conversations

```typescript
import { meteredModel } from '@stripe/ai-sdk/meter';
import { google } from '@ai-sdk/google';
import { generateText } from 'ai';

const model = meteredModel(
  google('gemini-2.5-flash'),
  process.env.STRIPE_API_KEY,
  'cus_xxxxx'
);

const result = await generateText({
  model,
  messages: [
    { role: 'user', content: 'What is the capital of France?' },
    { role: 'assistant', content: 'The capital of France is Paris.' },
    { role: 'user', content: 'What is its population?' },
  ],
});
```

### Using different providers

```typescript
import { meteredModel } from '@stripe/ai-sdk/meter';
import { openai } from '@ai-sdk/openai';
import { anthropic } from '@ai-sdk/anthropic';
import { google } from '@ai-sdk/google';

const STRIPE_API_KEY = process.env.STRIPE_API_KEY;
const CUSTOMER_ID = 'cus_xxxxx';

// OpenAI
const gptModel = meteredModel(
  openai('gpt-4o-mini'),
  STRIPE_API_KEY,
  CUSTOMER_ID
);

// Anthropic
const claudeModel = meteredModel(
  anthropic('claude-3-5-haiku-20241022'),
  STRIPE_API_KEY,
  CUSTOMER_ID
);

// Google
const geminiModel = meteredModel(
  google('gemini-2.5-flash'),
  STRIPE_API_KEY,
  CUSTOMER_ID
);
```

## How it works

The wrapper intercepts calls to the underlying language model and:

1. **Forwards the Request**: Passes all parameters to the original model unchanged
2. **Captures Usage**: Extracts token usage information from the response
3. **Reports to Stripe**: Sends meter events to Stripe asynchronously
4. **Returns Response**: Returns the original response without modification

For streaming responses, the wrapper collects usage information from the final stream chunk and reports it after the stream completes.

## Stripe meter events

Each API call generates meter events sent to Stripe:

**Input tokens event:**
```javascript
{
  event_name: 'token-billing-tokens',
  payload: {
    stripe_customer_id: 'cus_xxxxx',
    value: '100',
    model: 'openai/gpt-4o-mini',
    token_type: 'input'
  }
}
```

**Output tokens event:**
```javascript
{
  event_name: 'token-billing-tokens',
  payload: {
    stripe_customer_id: 'cus_xxxxx',
    value: '50',
    model: 'openai/gpt-4o-mini',
    token_type: 'output'
  }
}
```

## Error handling

The wrapper handles errors gracefully:

- **Invalid Models**: TypeScript prevents usage of v1 models at compile time
- **Missing Customer ID**: Throws an error immediately
- **Stripe API Errors**: Logged to console but don't interrupt AI generation
- **Missing Usage Data**: Handles responses without usage information

## Additional resources

- [Stripe Meter Events Documentation](https://docs.stripe.com/api/billing/meter-event)
- [Stripe Token Billing Documentation](https://docs.stripe.com/billing/token-billing)
- [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)
- [AI SDK Providers](https://sdk.vercel.ai/docs/providers)
- [Example Applications](./examples/)


```

--------------------------------------------------------------------------------
/llm/ai-sdk/provider/README.md:
--------------------------------------------------------------------------------

```markdown
# Stripe AI SDK Provider

The Stripe AI SDK Provider enables seamless integration with leading AI models through Stripe's unified LLM proxy at `llm.stripe.com`. This custom provider for the Vercel AI SDK automatically tracks token usage and integrates with Stripe's billing system, making it easy to monetize AI features in your applications.

> **Note:** This is part of the [`@stripe/ai-sdk`](../README.md) package. See the main README for an overview of all available tools.

## Private preview access required

The Stripe AI SDK Provider is currently only available to organizations participating in the Billing for LLM Tokens Private Preview. If you do not have access and would like to request it, please visit:

**[Request Access to Billing for LLM Tokens Private Preview](https://docs.stripe.com/billing/token-billing)**

## Why use Stripe AI SDK Provider?

- **Automatic Usage Tracking**: Token consumption is automatically tracked and reported to Stripe for billing
- **Multi-Model Support**: Access models from OpenAI, Google Gemini, and Anthropic Claude through a single API
- **Built-in Billing**: Seamlessly integrate AI costs into your existing Stripe billing workflow
- **Customer Attribution**: Automatically attribute usage to specific customers for accurate billing
- **Production-Ready**: Enterprise-grade infrastructure with Stripe's reliability
- **Transparent Costs**: Track and bill AI usage alongside your other Stripe products

Learn more about Stripe's Token Billing in the [Stripe Documentation](https://docs.stripe.com/billing/token-billing).

## Setup

The Stripe AI SDK Provider is available in the `@stripe/ai-sdk` package. You can install it with:

```bash
npm install @stripe/ai-sdk
```

## Provider instance

To create a Stripe provider instance, use the `createStripe` function:

```typescript
import { createStripe } from '@stripe/ai-sdk/provider';

const stripeLLM = createStripe({
  apiKey: process.env.STRIPE_API_KEY,
  customerId: 'cus_xxxxx', // Optional default customer ID
});
```

### Configuration options

- `apiKey` (required): Your Stripe API key from the [Stripe Dashboard](https://dashboard.stripe.com/apikeys)
- `customerId` (optional): Default customer ID to attribute usage to
- `baseURL` (optional): Custom base URL (defaults to `https://llm.stripe.com`)
- `headers` (optional): Additional headers to include in requests

## Supported models

The Stripe provider supports models from multiple providers through a unified interface. Specify models using the format `provider/model-name`:

### OpenAI models

```typescript
const model = stripe('openai/gpt-5');
const miniModel = stripe('openai/gpt-5-mini');
const reasoningModel = stripe('openai/o3');
```

**Available models:**
- `openai/gpt-5`, `openai/gpt-5-mini`, `openai/gpt-5-nano`
- `openai/gpt-4.1`, `openai/gpt-4.1-mini`, `openai/gpt-4.1-nano`
- `openai/gpt-4o`, `openai/gpt-4o-mini`
- `openai/o3`, `openai/o3-mini`, `openai/o3-pro`
- `openai/o1`, `openai/o1-mini`, `openai/o1-pro`

### Google Gemini models

```typescript
const model = stripe('google/gemini-2.5-pro');
const fastModel = stripe('google/gemini-2.5-flash');
```

**Available models:**
- `google/gemini-2.5-pro`
- `google/gemini-2.5-flash`, `google/gemini-2.5-flash-lite`
- `google/gemini-2.0-flash`, `google/gemini-2.0-flash-lite`

### Anthropic Claude models

```typescript
const model = stripe('anthropic/claude-sonnet-4');
const capableModel = stripe('anthropic/claude-opus-4');
```

**Available models:**
- `anthropic/claude-opus-4`, `anthropic/claude-opus-4-1`
- `anthropic/claude-sonnet-4`, `anthropic/claude-3-7-sonnet`
- `anthropic/claude-3-5-haiku`, `anthropic/claude-3-haiku`

## Examples

### Generate text

```typescript
import { createStripe } from '@stripe/ai-sdk/provider';
import { generateText } from 'ai';

const stripeLLM = createStripe({
  apiKey: process.env.STRIPE_API_KEY,
  customerId: 'cus_xxxxx',
});

const { text } = await generateText({
  model: stripe('openai/gpt-5'),
  prompt: 'What are the three primary colors?',
});

console.log(text);
```

### Stream text

```typescript
import { createStripe } from '@stripe/ai-sdk/provider';
import { streamText } from 'ai';

const stripeLLM = createStripe({
  apiKey: process.env.STRIPE_API_KEY,
  customerId: 'cus_xxxxx',
});

const result = streamText({
  model: stripe('google/gemini-2.5-flash'),
  prompt: 'Write a short story about AI.',
});

for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}
```

### Multi-turn conversations

```typescript
import { createStripe } from '@stripe/ai-sdk/provider';
import { generateText } from 'ai';

const stripeLLM = createStripe({
  apiKey: process.env.STRIPE_API_KEY,
  customerId: 'cus_xxxxx',
});

const result = await generateText({
  model: stripe('openai/gpt-4.1'),
  messages: [
    { role: 'user', content: 'What is the capital of France?' },
    { role: 'assistant', content: 'The capital of France is Paris.' },
    { role: 'user', content: 'What is its population?' },
  ],
});

console.log(result.text);
```

## Customer ID management

The Stripe provider offers flexible customer ID configuration to ensure accurate billing attribution. Customer IDs can be specified at three levels (in order of priority):

### Per-request setting (highest priority)

```typescript
await generateText({
  model: stripe('openai/gpt-5'),
  prompt: 'Hello!',
  providerOptions: {
    stripe: {
      customerId: 'cus_request_specific',
    },
  },
});
```

### Model-level setting

```typescript
const model = stripe('openai/gpt-5', {
  customerId: 'cus_model_level',
});

await generateText({
  model,
  prompt: 'Hello!',
});
```

### Provider-level setting

```typescript
const stripeLLM = createStripe({
  apiKey: process.env.STRIPE_API_KEY,
  customerId: 'cus_provider_level',
});
```

### Usage tracking

Access token usage information after generation:

```typescript
const result = await generateText({
  model: stripe('openai/gpt-5'),
  prompt: 'Hello!',
});

console.log(result.usage);
// { inputTokens: 2, outputTokens: 10, totalTokens: 12 }
```

## Supported AI SDK features

The Stripe provider supports the following AI SDK features:

- **Text Generation**: Both streaming and non-streaming
- **Multi-turn Conversations**: Complex conversation histories
- **Streaming**: Real-time token streaming
- **Temperature & Sampling**: All standard generation parameters
- **Stop Sequences**: Custom stop sequence support
- **Token Limits**: Max output tokens configuration

### Feature limitations

- **Tool Calling**: Function calling and tool use aren't currently supported by the llm.stripe.com API
- **Text Embeddings**: Embedding models aren't supported yet
- **Image Generation**: Image models aren't supported yet

## Additional resources

- [Stripe Token Billing Documentation](https://docs.stripe.com/billing/token-billing)
- [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)
- [AI SDK Custom Providers Guide](https://sdk.vercel.ai/docs/providers/custom-providers)
- [Example Applications](./examples/)

```

--------------------------------------------------------------------------------
/llm/token-meter/README.md:
--------------------------------------------------------------------------------

```markdown
# Stripe Token Meter

Generic token metering for native AI SDKs with automatic Stripe billing integration. Track and bill token usage from OpenAI, Anthropic, and Google Gemini without any framework dependencies.

## Private preview access required

Stripe Billing for LLM Tokens is currently only available to organizations participating in the Billing for LLM Tokens Private Preview. If you do not have access and would like to request it, please visit:

**[Request Access to Billing for LLM Tokens Private Preview](https://docs.stripe.com/billing/token-billing)**

## Why use Stripe Token Meter?

- **Native SDK Support**: Works directly with native AI SDKs (OpenAI, Anthropic, Google)
- **No Framework Required**: Direct integration without Vercel AI SDK or other frameworks
- **Automatic Detection**: Automatically detects provider and response types
- **Streaming Support**: Full support for streaming responses from all providers
- **Fire-and-Forget**: Billing events are sent asynchronously without blocking
- **Universal API**: Single interface works across all supported providers

## Installation

```bash
npm install @stripe/token-meter
```

## Supported providers

- **OpenAI**: Chat Completions, Responses API, Embeddings (streaming and non-streaming)
- **Anthropic**: Messages API (streaming and non-streaming)
- **Google Gemini**: GenerateContent API (streaming and non-streaming)

## Quick start

### OpenAI

```typescript
import OpenAI from 'openai';
import { createTokenMeter } from '@stripe/token-meter';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const meter = createTokenMeter(process.env.STRIPE_API_KEY);

// Non-streaming
const response = await openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'Hello!' }],
});

meter.trackUsage(response, 'cus_xxxxx');
```

### Anthropic

```typescript
import Anthropic from '@anthropic-ai/sdk';
import { createTokenMeter } from '@stripe/token-meter';

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const meter = createTokenMeter(process.env.STRIPE_API_KEY);

// Non-streaming
const response = await anthropic.messages.create({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello!' }],
});

meter.trackUsage(response, 'cus_xxxxx');
```

### Google Gemini

```typescript
import { GoogleGenerativeAI } from '@google/generative-ai';
import { createTokenMeter } from '@stripe/token-meter';

const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);
const meter = createTokenMeter(process.env.STRIPE_API_KEY);

const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' });
const response = await model.generateContent('Hello!');

meter.trackUsage(response.response, 'cus_xxxxx');
```

## API reference

### `createTokenMeter(stripeApiKey, config?)`

Creates a token meter instance for tracking usage.

**Parameters:**
- `stripeApiKey` (string): Your Stripe API key
- `config` (optional): Configuration options
  - `meterEventName` (string): Custom meter event name (default: 'token-billing-tokens')

**Returns:** TokenMeter instance

### `TokenMeter.trackUsage(response, customerId)`

Tracks usage from a non-streaming response (fire-and-forget).

**Parameters:**
- `response`: The response object from OpenAI, Anthropic, or Google
- `customerId` (string): Stripe customer ID to attribute usage to

**Supported response types:**
- `OpenAI.ChatCompletion`
- `OpenAI.Responses.Response`
- `OpenAI.CreateEmbeddingResponse`
- `Anthropic.Messages.Message`
- `GenerateContentResult` (Gemini)

### `TokenMeter.trackUsageStreamOpenAI(stream, customerId)`

Wraps an OpenAI streaming response for usage tracking.

**Parameters:**
- `stream`: OpenAI stream (Chat Completions or Responses API)
- `customerId` (string): Stripe customer ID

**Returns:** The wrapped stream (can be consumed normally)

**Important:** For OpenAI streaming, include `stream_options: { include_usage: true }` in your request.

### `TokenMeter.trackUsageStreamAnthropic(stream, customerId)`

Wraps an Anthropic streaming response for usage tracking.

**Parameters:**
- `stream`: Anthropic message stream
- `customerId` (string): Stripe customer ID

**Returns:** The wrapped stream (can be consumed normally)

### `TokenMeter.trackUsageStreamGemini(stream, customerId, modelName)`

Wraps a Google Gemini streaming response for usage tracking.

**Parameters:**
- `stream`: Gemini streaming result
- `customerId` (string): Stripe customer ID
- `modelName` (string): Model name (e.g., 'gemini-2.5-flash')

**Returns:** The wrapped stream (can be consumed normally)

## Examples

### OpenAI streaming

```typescript
import OpenAI from 'openai';
import { createTokenMeter } from '@stripe/token-meter';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const meter = createTokenMeter(process.env.STRIPE_API_KEY);

const stream = await openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'Count to 5' }],
  stream: true,
  stream_options: { include_usage: true }, // Required for metering
});

const meteredStream = meter.trackUsageStreamOpenAI(stream, 'cus_xxxxx');

for await (const chunk of meteredStream) {
  process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
```

### Anthropic streaming

```typescript
import Anthropic from '@anthropic-ai/sdk';
import { createTokenMeter } from '@stripe/token-meter';

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const meter = createTokenMeter(process.env.STRIPE_API_KEY);

const stream = await anthropic.messages.create({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Count to 5' }],
  stream: true,
});

const meteredStream = meter.trackUsageStreamAnthropic(stream, 'cus_xxxxx');

for await (const event of meteredStream) {
  if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
    process.stdout.write(event.delta.text);
  }
}
```

### Google Gemini streaming

```typescript
import { GoogleGenerativeAI } from '@google/generative-ai';
import { createTokenMeter } from '@stripe/token-meter';

const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);
const meter = createTokenMeter(process.env.STRIPE_API_KEY);

const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' });
const result = await model.generateContentStream('Count to 5');

const meteredStream = meter.trackUsageStreamGemini(
  result,
  'cus_xxxxx',
  'gemini-2.5-flash'
);

for await (const chunk of meteredStream.stream) {
  process.stdout.write(chunk.text());
}
```

### OpenAI Responses API

```typescript
import OpenAI from 'openai';
import { createTokenMeter } from '@stripe/token-meter';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const meter = createTokenMeter(process.env.STRIPE_API_KEY);

const response = await openai.responses.create({
  model: 'gpt-4o-mini',
  input: 'What is 2+2?',
  instructions: 'You are a helpful math assistant.',
});

meter.trackUsage(response, 'cus_xxxxx');
console.log('Output:', response.output);
```

### OpenAI embeddings

```typescript
import OpenAI from 'openai';
import { createTokenMeter } from '@stripe/token-meter';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const meter = createTokenMeter(process.env.STRIPE_API_KEY);

const response = await openai.embeddings.create({
  model: 'text-embedding-3-small',
  input: 'Hello, world!',
});

meter.trackUsage(response, 'cus_xxxxx');
console.log('Embedding dimensions:', response.data[0].embedding.length);
```

## How it works

The token meter:

1. **Detects Provider**: Automatically identifies the AI provider from the response
2. **Extracts Usage**: Pulls token counts from the response object
3. **Reports to Stripe**: Sends meter events asynchronously to Stripe
4. **Non-Blocking**: Never interrupts your application flow

For streaming responses, the meter wraps the stream and reports usage after the stream completes.

## Stripe meter events

Each API call generates meter events sent to Stripe:

**Input tokens event:**
```javascript
{
  event_name: 'token-billing-tokens',
  payload: {
    stripe_customer_id: 'cus_xxxxx',
    value: '100',
    model: 'openai/gpt-4o-mini',
    token_type: 'input'
  }
}
```

**Output tokens event:**
```javascript
{
  event_name: 'token-billing-tokens',
  payload: {
    stripe_customer_id: 'cus_xxxxx',
    value: '50',
    model: 'openai/gpt-4o-mini',
    token_type: 'output'
  }
}
```

## Error handling

The token meter handles errors gracefully:

- **Stripe API Errors**: Logged to console but don't interrupt your application
- **Missing Usage Data**: Handles responses without usage information
- **Invalid Provider**: Logs a warning for unrecognized providers

## TypeScript support

Full TypeScript support with type definitions for all providers:

```typescript
import type { TokenMeter, SupportedResponse, SupportedStream } from '@stripe/token-meter';
```

## Comparison with AI SDK Meter

### Use Token Meter when
- You're using native SDKs (OpenAI, Anthropic, Google) directly
- You don't want to depend on Vercel AI SDK
- You need maximum control over API parameters
- You're working with embeddings or specialized APIs

### Use AI SDK Meter when
- You're already using Vercel AI SDK
- You want a unified interface across providers
- You need AI SDK-specific features (tool calling abstractions, etc.)
- You prefer the AI SDK's streaming abstractions

## Additional resources

- [Stripe Meter Events Documentation](https://docs.stripe.com/api/billing/meter-event)
- [Stripe Token Billing Documentation](https://docs.stripe.com/billing/token-billing)
- [OpenAI API Documentation](https://platform.openai.com/docs/api-reference)
- [Anthropic API Documentation](https://docs.anthropic.com/claude/reference)
- [Google Gemini API Documentation](https://ai.google.dev/docs)
- [Example Applications](./examples/)

## License

MIT


```

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

```markdown
# Security Policy

### Reporting a vulnerability

Please do not open GitHub issues or pull requests - this makes the problem immediately visible to everyone, including malicious actors.   

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).
Stripe's security team will triage your report and respond according to its impact on Stripe users and systems.

```

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

```markdown
# Contributing

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). 

<!-- We will try and respond to your issue or pull request within a week. -->

To make changes yourself, follow these steps:

1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository and [clone](https://help.github.com/articles/cloning-a-repository/) it locally.
<!-- 1. TODO add install step(s), e.g. "Run `npm install`" -->
<!-- 1. TODO add build step(s), e.g. "Build the library using `npm run build`" -->
2. Make your changes
<!-- 1. TODO add test step(s), e.g. "Test your changes with `npm test`" -->
3. Submit a [pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)

## Contributor License Agreement ([CLA](https://en.wikipedia.org/wiki/Contributor_License_Agreement))

Once you have submitted a pull request, sign the CLA by clicking on the badge in the comment from [@CLAassistant](https://github.com/CLAassistant).

<img width="910" alt="image" src="https://user-images.githubusercontent.com/62121649/198740836-70aeb322-5755-49fc-af55-93c8e8a39058.png">

<br />
Thanks for contributing to Stripe! :sparkles:

```

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

```markdown
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
  advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
  address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [email protected]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

```

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

```python

```

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

```python

```

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

```python

```

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

```yaml
packages:
  - '.'
  - 'examples/*'

```

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

```typescript
import StripeAgentToolkit from './toolkit';
export {StripeAgentToolkit};

```

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

```typescript
import StripeAgentToolkit from './toolkit';
export {StripeAgentToolkit};

```

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

```typescript
import StripeAgentToolkit from './toolkit';
export {StripeAgentToolkit};

```

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

```python
"""Stripe Agent Toolkit for Strands."""

from .toolkit import StripeAgentToolkit

__all__ = ["StripeAgentToolkit"]

```

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

```typescript
import StripeAgentToolkit from './toolkit';
import {registerPaidTool} from './register-paid-tool';
export {StripeAgentToolkit, registerPaidTool};

```

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

```json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "dist"
  },
  "include": ["index.ts"],
  "exclude": ["node_modules", "dist"]
}

```

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

```json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "dist"
  },
  "include": ["index.ts"],
  "exclude": ["node_modules", "dist"]
}

```

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

```json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "dist"
  },
  "include": ["index.ts"],
  "exclude": ["node_modules", "dist"]
}

```

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

```json
{
  "name": "stripe",
  "version": "0.1.0",
  "mcpServers": {
    "stripe": {
      "httpUrl": "https://mcp.stripe.com",
      "oauth": {
        "enabled": true
      }
    }
  }
}

```

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

```json
{
  "recommendations": [
    "EditorConfig.editorconfig", // default
    "ms-python.python", // intellisense
    "ms-python.flake8", // linting
    "charliermarsh.ruff" // formatting
  ]
}

```

--------------------------------------------------------------------------------
/llm/token-meter/types.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Type definitions for token-billing
 * Re-exports shared types for backward compatibility
 */

export type {TokenUsage, UsageEvent, MeterConfig, Provider} from './meter-event-types';


```

--------------------------------------------------------------------------------
/llm/token-meter/index.ts:
--------------------------------------------------------------------------------

```typescript
// Main entry point for token-billing

export * from './types';
export {createTokenMeter} from './token-meter';
export type {TokenMeter, SupportedResponse, SupportedStream} from './token-meter';


```

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

```
twine
crewai==1.4.1
crewai-tools==1.4.1
flake8
langchain==1.0.4
langchain-openai==1.0.2
mypy==1.18.2
pydantic>=2.12.4
pyright==1.1.407
python-dotenv==1.2.1
ruff==0.14.4
stripe==13.2.0
openai==2.7.1
openai-agents==0.5.0

```

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

```typescript
// @ts-ignore
import emojiFromText from 'emoji-from-text';

export function generateImage(description: string) {
  const emoji = emojiFromText(description);
  try {
    return emoji[0].match.emoji.char;
  } catch (e) {
    return '⚠️ (Error generating image)';
  }
}

```

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

```typescript
import type {Config} from 'jest';

const config: Config = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/src'],
  testMatch: ['**/test/**/*.ts?(x)'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
};

export default config;

```

--------------------------------------------------------------------------------
/llm/ai-sdk/provider/examples/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "module": "commonjs",
    "noEmit": true
  },
  "ts-node": {
    "transpileOnly": true,
    "compilerOptions": {
      "module": "commonjs"
    }
  },
  "include": ["./**/*.ts"],
  "exclude": ["node_modules", "dist"]
}


```

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

```typescript
import type {Config} from 'jest';

const config: Config = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/src'],
  testMatch: ['**/test/**/*.ts?(x)'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
};

export default config;

```

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

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

```

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

```yaml
blank_issues_enabled: false
contact_links:
  - name: Stripe support
    url: https://support.stripe.com/
    about: |
      Please only file issues here that you believe represent actual bugs or feature requests for the Stripe Agent Tools library.

      If you're having general trouble with your Stripe integration, please reach out to support.

```

--------------------------------------------------------------------------------
/llm/ai-sdk/provider/tsconfig.build.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "types": ["node"]
  },
  "include": [
    "*.ts"
  ],
  "exclude": [
    "node_modules",
    "dist",
    "tests",
    "examples",
    "coverage",
    "**/*.test.ts",
    "**/*.spec.ts",
    "jest.config.ts",
    "tsup.config.ts"
  ]
}


```

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

```python
from os import getenv

from dotenv import load_dotenv

# Load the environment
load_dotenv()


def ensure(name: str) -> str:
    var = getenv(name)
    if not var:
        raise ValueError(f"Missing '{name}' environment variable")
    return var


def get_or(name: str, default: str) -> str:
    var = getenv(name)
    if not var:
        return default
    return var

```

--------------------------------------------------------------------------------
/llm/ai-sdk/provider/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Stripe AI SDK Provider
 * Custom provider for Vercel AI SDK that integrates with Stripe's llm.stripe.com proxy
 */

export {createStripe, stripe, type StripeProvider} from './stripe-provider';
export {StripeLanguageModel, StripeProviderAccessError} from './stripe-language-model';
export type {
  StripeLanguageModelSettings,
  StripeProviderConfig,
  StripeProviderOptions,
} from './types';


```

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

```dockerfile
# syntax=docker/dockerfile:1
# check=experimental=all

FROM node:22-alpine@sha256:9bef0ef1e268f60627da9ba7d7605e8831d5b56ad07487d24d1aa386336d1944
RUN npm install -g typescript pnpm
RUN addgroup -S group && adduser -S user -G group
WORKDIR /app
COPY . .
RUN --mount=type=cache,target=/root/.local \
    pnpm install --frozen-lockfile && pnpm run build

USER user
ENTRYPOINT ["node", "/app/dist/index.js"]

```

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

```json
{
  "name": "stripe-agent-toolkit-examples-openai",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "dotenv": "^16.4.5",
    "openai": "^4.86.1",
    "@stripe/agent-toolkit": "workspace:*"
  },
  "devDependencies": {
    "@types/node": "^22.7.4"
  }
}

```

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

```typescript
import {tool} from 'ai';
import {z} from 'zod';
import StripeAPI from '../shared/api';

export default function StripeTool(
  stripeAPI: StripeAPI,
  method: string,
  description: string,
  schema: z.ZodObject<any, any, any, any, {[x: string]: any}>
) {
  return tool({
    description,
    inputSchema: schema,
    execute: (arg: z.output<typeof schema>) => {
      return stripeAPI.run(method, arg);
    },
  });
}

```

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

```json
{
  "editor.formatOnSave": true,
  "python.defaultInterpreterPath": "./venv/bin/python",
  "[python]": {
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.codeActionsOnSave": {
      "source.organizeImports": "never"
    }
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "ruff.lint.enable": false
}

```

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

```json
{
  "name": "stripe-agent-toolkit-examples-ai-sdk",
  "version": "0.1.0",
  "description": "",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@ai-sdk/openai": "^2.0.58",
    "@stripe/agent-toolkit": "workspace:*",
    "ai": "^5.0.89",
    "dotenv": "^16.4.5",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@types/node": "^22.7.4"
  }
}

```

--------------------------------------------------------------------------------
/tools/modelcontextprotocol/server.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json",
  "name": "com.stripe/mcp",
  "description": "MCP server integrating with Stripe - tools for customers, products, payments, and more.",
  "repository": {
    "url": "https://github.com/stripe/ai",
    "source": "github"
  },
  "version": "0.2.4",
  "remotes": [
    {
      "type": "streamable-http",
      "url": "https://mcp.stripe.com"
    }
  ]
}

```

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

```toml
[project]
name = "email-agent"
version = "0.1.0"
description = "An automated email support agent that uses AI to respond to customer support emails"
requires-python = ">=3.9"
dependencies = [
    "python-dotenv>=1.2.1",
    "imaplib2==3.6",
    "python-decouple==3.8",
    "openai-agents==0.5.0",
    "stripe-agent-toolkit>=0.6.2",
    "stripe>=13.2.0",
    "urllib3<3",
    "markdown==3.7"
]

[tool.hatch.metadata]
allow-direct-references = true

```

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

```json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Default",
  "compilerOptions": {
    "outDir": "./dist",
    "target": "es2022",
    "moduleDetection": "force",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "strict": true,
    "module": "NodeNext",
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "examples"
  ]
}
```

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

```json
{
  "name": "stripe-agent-toolkit-examples-langchain",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@langchain/core": "^0.3.6",
    "@langchain/openai": "^0.3.5",
    "@stripe/agent-toolkit": "workspace:*",
    "dotenv": "^16.4.5",
    "langchain": "^0.3.2"
  },
  "devDependencies": {
    "@types/node": "^22.7.4"
  }
}

```

--------------------------------------------------------------------------------
/llm/ai-sdk/meter/types.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Type definitions for AI SDK metering
 */

import type {Provider} from './meter-event-types';

/**
 * Configuration options for AI SDK metering
 */
export interface AIMeterConfig {
  /**
   * Stripe API key
   */
  stripeApiKey: string;

  /**
   * Stripe customer ID for meter events
   */
  stripeCustomerId: string;
}

/**
 * Usage information extracted from AI SDK responses
 */
export interface AIUsageInfo {
  provider: Provider;
  model: string;
  inputTokens: number;
  outputTokens: number;
}


```

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

```json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "vcs": {
    "enabled": false,
    "clientKind": "git",
    "useIgnoreFile": false
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": ["worker-configuration.d.ts"]
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "tab"
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "double"
    }
  }
}

```

--------------------------------------------------------------------------------
/llm/token-meter/jest.config.ts:
--------------------------------------------------------------------------------

```typescript
import type {Config} from 'jest';

const config: Config = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/tests'],
  testMatch: ['**/*.test.ts'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  modulePaths: ['<rootDir>/node_modules'],
  collectCoverageFrom: [
    '<rootDir>/*.ts',
    '<rootDir>/utils/**/*.ts',
    '!<rootDir>/*.d.ts',
    '!<rootDir>/node_modules/**',
  ],
  coverageDirectory: '<rootDir>/coverage',
  verbose: true,
  rootDir: '.',
};

export default config;


```

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

```json
{
  "compilerOptions": {
    "target": "es2021",
    "lib": [
      "es2021"
    ],
    "jsx": "react-jsx",
    "module": "es2022",
    "moduleResolution": "Bundler",
    "resolveJsonModule": true,
    "allowJs": true,
    "checkJs": false,
    "noEmit": true,
    "isolatedModules": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "allowImportingTsExtensions": true,
    "strict": true,
    "skipLibCheck": true,
    "types": []
  },
  "include": [
    "worker-configuration.d.ts",
    "src/**/*.ts"
  ]
}
```

--------------------------------------------------------------------------------
/llm/ai-sdk/meter/examples/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "moduleResolution": "node",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "types": ["node"],
    "noEmit": true
  },
  "ts-node": {
    "transpileOnly": true,
    "compilerOptions": {
      "module": "commonjs",
      "moduleResolution": "node"
    }
  },
  "include": ["./**/*.ts"],
  "exclude": ["node_modules", "dist"]
}


```

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

```typescript
import {createInvoiceItemPrompt} from '@/shared/invoiceItems/createInvoiceItem';

describe('createInvoiceItemPrompt', () => {
  it('should return the correct prompt when no customer is specified', () => {
    const prompt = createInvoiceItemPrompt({});
    expect(prompt).toContain('- customer (str)');
  });

  it('should return the correct prompt when a customer is specified', () => {
    const prompt = createInvoiceItemPrompt({customer: 'cus_123'});
    expect(prompt).toContain('context: cus_123');
    expect(prompt).not.toContain('- customer (str)');
  });
});

```

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

```python
import asyncio

from agents import ItemHelpers, TResponseInputItem

import support_agent


async def main():
    """Simple REPL for testing your support agent"""
    input_items: list[TResponseInputItem] = []
    while True:
        user_input = input("Enter your message: ")
        input_items.append({"content": user_input, "role": "user"})
        result = await support_agent.run(input_items)
        output = ItemHelpers.text_message_outputs(result.new_items)
        print(f"Assistant: {output}")
        input_items = result.to_input_list()


if __name__ == "__main__":
    asyncio.run(main())

```

--------------------------------------------------------------------------------
/llm/token-meter/tsconfig.build.json:
--------------------------------------------------------------------------------

```json
{
    "$schema": "https://json.schemastore.org/tsconfig",
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "outDir": "./dist",
        "rootDir": ".",
        "declaration": true,
        "declarationMap": true,
        "sourceMap": true
    },
    "include": [
        "index.ts",
        "token-meter.ts",
        "meter-event-logging.ts",
        "meter-event-types.ts",
        "types.ts",
        "utils/**/*.ts"
    ],
    "exclude": [
        "node_modules",
        "dist",
        "coverage",
        "tests",
        "examples",
        "**/*.test.ts",
        "**/*.spec.ts"
    ]
}
```

--------------------------------------------------------------------------------
/llm/ai-sdk/provider/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "target": "ES2022",
    "module": "CommonJS",
    "moduleResolution": "Node",
    "lib": ["ES2022"],
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "isolatedModules": true,
    "types": ["node", "jest"]
  },
  "include": [
    "*.ts",
    "tests/**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "dist",
    "examples",
    "coverage"
  ]
}


```

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

```typescript
import {retrieveBalanceParameters} from '@/shared/balance/retrieveBalance';

describe('retrieveBalanceParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = retrieveBalanceParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual([]);
    expect(fields.length).toBe(0);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = retrieveBalanceParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual([]);
    expect(fields.length).toBe(0);
  });
});

```

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

```python
"""
This tool allows agents to interact with the Stripe API.
"""

from __future__ import annotations

from typing import Any, Optional, Type
from pydantic import BaseModel

from crewai.tools import BaseTool

from ..api import StripeAPI


class StripeTool(BaseTool):
    """Tool for interacting with the Stripe API."""

    stripe_api: StripeAPI
    method: str
    name: str = ""
    description: str = ""
    args_schema: Optional[Type[BaseModel]] = None

    def _run(
        self,
        *args: Any,
        **kwargs: Any,
    ) -> str:
        """Use the Stripe API to run an operation."""
        return self.stripe_api.run(self.method, *args, **kwargs)

```

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

```python
"""
This tool allows agents to interact with the Stripe API.
"""

from __future__ import annotations

from typing import Any, Optional, Type
from pydantic import BaseModel

from langchain.tools import BaseTool

from ..api import StripeAPI


class StripeTool(BaseTool):
    """Tool for interacting with the Stripe API."""

    stripe_api: StripeAPI
    method: str
    name: str = ""
    description: str = ""
    args_schema: Optional[Type[BaseModel]] = None

    def _run(
        self,
        *args: Any,
        **kwargs: Any,
    ) -> str:
        """Use the Stripe API to run an operation."""
        return self.stripe_api.run(self.method, *args, **kwargs)

```

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

```typescript
import {createRefundParameters} from '@/shared/refunds/createRefund';

describe('createRefundParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = createRefundParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['payment_intent', 'amount']);
    expect(fields.length).toBe(2);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = createRefundParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['payment_intent', 'amount']);
    expect(fields.length).toBe(2);
  });
});

```

--------------------------------------------------------------------------------
/llm/ai-sdk/meter/meter-event-types.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Shared type definitions for metering
 */

/**
 * Token usage information
 */
export interface TokenUsage {
  inputTokens: number;
  outputTokens: number;
}

/**
 * Usage event data that gets logged to Stripe
 */
export interface UsageEvent {
  model: string;
  provider: string;
  usage: TokenUsage;
  stripeCustomerId: string;
}

/**
 * Configuration options for Stripe integration
 */
export interface MeterConfig {}

/**
 * Provider identifier - any string representing the AI provider
 * Common values: 'openai', 'anthropic', 'google', 'azure', 'bedrock', etc.
 * The provider name is normalized to lowercase from the model's provider string.
 */
export type Provider = string;


```

--------------------------------------------------------------------------------
/llm/token-meter/meter-event-types.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Shared type definitions for metering
 */

/**
 * Token usage information
 */
export interface TokenUsage {
  inputTokens: number;
  outputTokens: number;
}

/**
 * Usage event data that gets logged to Stripe
 */
export interface UsageEvent {
  model: string;
  provider: string;
  usage: TokenUsage;
  stripeCustomerId: string;
}

/**
 * Configuration options for Stripe integration
 */
export interface MeterConfig {}

/**
 * Provider identifier - any string representing the AI provider
 * Common values: 'openai', 'anthropic', 'google', 'azure', 'bedrock', etc.
 * The provider name is normalized to lowercase from the model's provider string.
 */
export type Provider = string;


```

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

```typescript
import {listPaymentIntentsParameters} from '@/shared/paymentIntents/listPaymentIntents';

describe('listPaymentIntentsParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = listPaymentIntentsParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['customer', 'limit']);
    expect(fields.length).toBe(2);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = listPaymentIntentsParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['limit']);
    expect(fields.length).toBe(1);
  });
});

```

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

```typescript
import {createPaymentLinkParameters} from '@/shared/paymentLinks/createPaymentLink';

describe('createPaymentLinkParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = createPaymentLinkParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['price', 'quantity', 'redirect_url']);
    expect(fields.length).toBe(3);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = createPaymentLinkParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['price', 'quantity', 'redirect_url']);
  });
});

```

--------------------------------------------------------------------------------
/llm/ai-sdk/meter/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": ".",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "isolatedModules": true,
    "types": ["jest", "node"],
    "baseUrl": ".",
    "paths": {
      "*": ["node_modules/*"]
    }
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "dist",
    "coverage"
  ]
}


```

--------------------------------------------------------------------------------
/llm/token-meter/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": ".",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "isolatedModules": true,
    "types": ["jest", "node"],
    "baseUrl": ".",
    "paths": {
      "*": ["node_modules/*"]
    }
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "dist",
    "coverage"
  ]
}


```

--------------------------------------------------------------------------------
/llm/ai-sdk/jest.config.ts:
--------------------------------------------------------------------------------

```typescript
import type {Config} from 'jest';

const config: Config = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  roots: ['<rootDir>/provider/tests', '<rootDir>/meter/tests'],
  testMatch: ['**/*.test.ts'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  modulePaths: ['<rootDir>/node_modules'],
  collectCoverageFrom: [
    '<rootDir>/provider/**/*.ts',
    '<rootDir>/meter/**/*.ts',
    '!<rootDir>/**/*.d.ts',
    '!<rootDir>/node_modules/**',
    '!<rootDir>/**/tests/**',
    '!<rootDir>/**/examples/**',
  ],
  coverageDirectory: '<rootDir>/coverage',
  verbose: true,
  rootDir: '.',
  globals: {
    'ts-jest': {
      isolatedModules: true,
    },
  },
};

export default config;


```

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

```typescript
import {createInvoiceItemParameters} from '@/shared/invoiceItems/createInvoiceItem';

describe('createInvoiceItemParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = createInvoiceItemParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['customer', 'price', 'invoice']);
    expect(fields.length).toBe(3);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = createInvoiceItemParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['price', 'invoice']);
    expect(fields.length).toBe(2);
  });
});

```

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

```typescript
import {searchDocumentationParameters} from '@/shared/documentation/searchDocumentation';

describe('searchDocumentationParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = searchDocumentationParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['question', 'language']);
    expect(fields.length).toBe(2);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = searchDocumentationParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['question', 'language']);
    expect(fields.length).toBe(2);
  });
});

```

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

```typescript
import {listPaymentIntentsPrompt} from '@/shared/paymentIntents/listPaymentIntents';

describe('listPaymentIntentsPrompt', () => {
  it('should return the correct prompt', () => {
    const prompt = listPaymentIntentsPrompt();
    expect(prompt).toContain('customer');
  });

  it('should return the correct prompt when no customer is specified', () => {
    const prompt = listPaymentIntentsPrompt({});
    expect(prompt).toContain('- customer (str, optional)');
  });

  it('should return the correct prompt when a customer is specified', () => {
    const prompt = listPaymentIntentsPrompt({customer: 'cus_123'});
    expect(prompt).toContain('context: cus_123');
    expect(prompt).not.toContain('- customer (str, optional)');
  });
});

```

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

```json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Jest Current File",
            "runtimeExecutable": "sh",
            "program": "${workspaceFolder}/typescript/node_modules/.bin/jest",
            "args": [
                "${relativeFile}",
                "--config",
                "${workspaceFolder}/typescript/jest.config.ts"
            ],
            "console": "integratedTerminal",
            "internalConsoleOptions": "openOnFirstSessionStart"
        }
    ]
}
```

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

```typescript
import {defineConfig} from 'tsup';

export default defineConfig([
  {
    entry: ['src/langchain/index.ts'],
    outDir: 'langchain',
    format: ['cjs', 'esm'],
    dts: true,
    sourcemap: true,
  },
  {
    entry: ['src/ai-sdk/index.ts'],
    outDir: 'ai-sdk',
    format: ['cjs', 'esm'],
    dts: true,
    sourcemap: true,
  },
  {
    entry: ['src/modelcontextprotocol/index.ts'],
    outDir: 'modelcontextprotocol',
    format: ['cjs', 'esm'],
    dts: true,
    sourcemap: true,
  },
  {
    entry: ['src/openai/index.ts'],
    outDir: 'openai',
    format: ['cjs', 'esm'],
    dts: true,
    sourcemap: true,
  },
  {
    entry: ['src/cloudflare/index.ts'],
    outDir: 'cloudflare',
    format: ['cjs', 'esm'],
    dts: true,
    sourcemap: true,
    external: ['cloudflare:workers'],
  },
]);

```

--------------------------------------------------------------------------------
/llm/ai-sdk/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
    "$schema": "https://json.schemastore.org/tsconfig",
    "compilerOptions": {
        "target": "ES2022",
        "module": "CommonJS",
        "moduleResolution": "Node",
        "lib": [
            "ES2022"
        ],
        "outDir": "dist",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "resolveJsonModule": true,
        "declaration": true,
        "declarationMap": true,
        "sourceMap": true,
        "isolatedModules": true,
        "types": [
            "node",
            "jest"
        ]
    },
    "include": [
        "provider/**/*.ts",
        "meter/**/*.ts"
    ],
    "exclude": [
        "node_modules",
        "dist",
        "provider/examples",
        "meter/examples",
        "coverage"
    ]
}
```

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

```python
import asyncio
import os

from dotenv import load_dotenv
load_dotenv()

from agents import Agent, Runner, WebSearchTool
from stripe_agent_toolkit.openai.toolkit import StripeAgentToolkit

stripe_agent_toolkit = StripeAgentToolkit(
    secret_key=os.getenv("STRIPE_SECRET_KEY"),
    configuration={},
)

research_agent = Agent(
    name="Research Agent",
    instructions="You are an expert at research.",
    tools=[WebSearchTool()],
    hooks=stripe_agent_toolkit.billing_hook(
        type="outcome",
        customer=os.getenv("STRIPE_CUSTOMER_ID"),
        meter=os.getenv("STRIPE_METER"),
    ),
)

async def main():
    result = await Runner.run(
        research_agent,
        "search the web for 'global gdp' and give me the latest data.",
    )
    print(result.final_output)

if __name__ == "__main__":
    asyncio.run(main())

```

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

```json
{
  "name": "remote-mcp-server",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "deploy": "wrangler deploy",
    "dev": "wrangler dev",
    "format": "biome format --write",
    "lint:fix": "biome lint --fix",
    "start": "wrangler dev",
    "cf-typegen": "wrangler types"
  },
  "devDependencies": {
    "@biomejs/biome": "1.9.4",
    "@cloudflare/workers-types": "^4.20250515.0",
    "typescript": "^5.8.3",
    "workers-mcp": "0.1.0-3",
    "wrangler": "^4.15.2"
  },
  "dependencies": {
    "@cloudflare/workers-oauth-provider": "^0.0.5",
    "@modelcontextprotocol/sdk": "^1.17.1",
    "@stripe/agent-toolkit": "workspace:*",
    "@types/node": "^22.15.18",
    "add": "^2.0.6",
    "agents": "^0.0.84",
    "dotenv": "^16.5.0",
    "emoji-from-text": "^1.1.13",
    "hono": "^4.10.3",
    "stripe": "^18.1.0",
    "zod": "^3.25.76"
  },
  "pnpm": {}
}

```

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

```python
import os
from dotenv import load_dotenv

from strands import Agent
from stripe_agent_toolkit.strands.toolkit import StripeAgentToolkit

load_dotenv()

# Initialize the Stripe Agent Toolkit
stripe_agent_toolkit = StripeAgentToolkit(
    secret_key=os.getenv("STRIPE_SECRET_KEY"),
    configuration={
        "actions": {
            "payment_links": {
                "create": True,
            },
            "products": {
                "create": True,
            },
            "prices": {
                "create": True,
            },
        }
    },
)

# Get the Stripe tools
tools = stripe_agent_toolkit.get_tools()

# Create agent with Stripe tools
agent = Agent(
    tools=tools
)

# Test the agent
response = agent("""
    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.
""")

print(response)

```

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

```python
from typing import Any
from agents import AgentHooks, RunContextWrapper, Agent, Tool
from ..api import StripeAPI

class BillingHooks(AgentHooks):
    def __init__(self, stripe: StripeAPI, type: str, customer: str, meter: str = None, meters: dict[str, str] = None):
        self.type = type
        self.stripe = stripe
        self.customer = customer
        self.meter = meter
        self.meters = meters

    async def on_end(self, context: RunContextWrapper, agent: Agent, output: Any) -> None:
        if self.type == "outcome":
            self.stripe.create_meter_event(self.meter, self.customer)

        if self.type == "token":
            if self.meters["input"]:
                self.stripe.create_meter_event(self.meters["input"], self.customer, context.usage.input_tokens)
            if self.meters["output"]:
                self.stripe.create_meter_event(self.meters["output"], self.customer, context.usage.output_tokens)

```

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

```typescript
import {z} from 'zod';
import {StructuredTool} from '@langchain/core/tools';
import {CallbackManagerForToolRun} from '@langchain/core/callbacks/manager';
import {RunnableConfig} from '@langchain/core/runnables';
import StripeAPI from '../shared/api';

class StripeTool extends StructuredTool {
  stripeAPI: StripeAPI;

  method: string;

  name: string;

  description: string;

  schema: z.ZodObject<any, any, any, any>;

  constructor(
    StripeAPI: StripeAPI,
    method: string,
    description: string,
    schema: z.ZodObject<any, any, any, any, {[x: string]: any}>
  ) {
    super();

    this.stripeAPI = StripeAPI;
    this.method = method;
    this.name = method;
    this.description = description;
    this.schema = schema;
  }

  _call(
    arg: z.output<typeof this.schema>,
    _runManager?: CallbackManagerForToolRun,
    _parentConfig?: RunnableConfig
  ): Promise<any> {
    return this.stripeAPI.run(this.method, arg);
  }
}

export default StripeTool;

```

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

```toml
[project]
name = "stripe-agent-toolkit"
version = "0.6.2"
description = "Stripe Agent Toolkit"
readme = "README.md"
license = {file = "LICENSE"}
authors = [
  {name = "Stripe", email = "[email protected]"}
]
keywords = ["stripe", "api", "payments"]

[project.urls]
"Bug Tracker" = "https://github.com/stripe/ai/issues"
"Source Code" = "https://github.com/stripe/ai"

[tool.setuptools.packages.find]
include = ["stripe_agent_toolkit*"]
exclude = ["tests*", "examples*"]

[tool.ruff]
# same as our black config
line-length = 79
extend-exclude = ["build"]

[tool.ruff.format]
# currently the default value, but opt-out in the future
docstring-code-format = false

[tool.pyright]
include = [
  "*",
]
exclude = ["build", "**/__pycache__"]
reportMissingTypeArgument = true
reportUnnecessaryCast = true
reportUnnecessaryComparison = true
reportUnnecessaryContains = true
reportUnnecessaryIsInstance = true
reportPrivateImportUsage = true
reportUnnecessaryTypeIgnoreComment = true

```

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

```typescript
import {BaseToolkit} from '@langchain/core/tools';
import StripeTool from './tool';
import StripeAPI from '../shared/api';
import tools from '../shared/tools';
import {isToolAllowed, type Configuration} from '../shared/configuration';

class StripeAgentToolkit implements BaseToolkit {
  private _stripe: StripeAPI;

  tools: StripeTool[];

  constructor({
    secretKey,
    configuration,
  }: {
    secretKey: string;
    configuration: Configuration;
  }) {
    this._stripe = new StripeAPI(secretKey, configuration.context);

    const context = configuration.context || {};
    const filteredTools = tools(context).filter((tool) =>
      isToolAllowed(tool, configuration)
    );

    this.tools = filteredTools.map(
      (tool) =>
        new StripeTool(
          this._stripe,
          tool.method,
          tool.description,
          tool.inputSchema
        )
    );
  }

  getTools(): StripeTool[] {
    return this.tools;
  }
}

export default StripeAgentToolkit;

```

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

```yaml
name: Feature request
description: Suggest an idea for this library
labels: ["feature-request"]
body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to fill out this feature request!
  - type: textarea
    id: problem
    attributes:
      label: Is your feature request related to a problem? Please describe.
      description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
  - type: textarea
    id: solution
    attributes:
      label: Describe the solution you'd like
      description: A clear and concise description of what you want to happen.
  - type: textarea
    id: alternatives
    attributes:
      label: Describe alternatives you've considered
      description: A clear and concise description of any alternative solutions or features you've considered.
  - type: textarea
    id: context
    attributes:
      label: Additional context
      description: Add any other context about the feature request here.

```

--------------------------------------------------------------------------------
/.github/workflows/npm_release_shared.yml:
--------------------------------------------------------------------------------

```yaml
name: NPM Release

on:
  workflow_dispatch:
    inputs:
      working_directory:
        description: 'Package to release'
        required: true
        type: choice
        options:
          - './tools/typescript'
          - './tools/modelcontextprotocol'
          - './llm/ai-sdk'
          - './llm/token-meter'

jobs:
  npm-release:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ${{ inputs.working_directory }}
    permissions:
      contents: read
      id-token: write
    steps:
      - uses: actions/checkout@v4

      - name: pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 9.11.0

      # Setup .npmrc file to publish to npm
      - uses: actions/setup-node@v4
        with:
          node-version: "20.x"
          registry-url: "https://registry.npmjs.org"

      - run: pnpm install
      - run: pnpm run --if-present test
      - run: pnpm run --if-present build
      - run: npm publish --ignore-scripts --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

```

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

```python
import os
from dotenv import load_dotenv

from langchain import hub
from langchain_openai import ChatOpenAI

from langgraph.prebuilt import create_react_agent

from stripe_agent_toolkit.langchain.toolkit import StripeAgentToolkit

load_dotenv()

llm = ChatOpenAI(
    model="gpt-4o",
)

stripe_agent_toolkit = StripeAgentToolkit(
    secret_key=os.getenv("STRIPE_SECRET_KEY"),
    configuration={
        "actions": {
            "payment_links": {
                "create": True,
            },
            "products": {
                "create": True,
            },
            "prices": {
                "create": True,
            },
        }
    },
)

tools = []
tools.extend(stripe_agent_toolkit.get_tools())

langgraph_agent_executor = create_react_agent(llm, tools)

input_state = {
    "messages": """
        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.
    """,
}

output_state = langgraph_agent_executor.invoke(input_state)

print(output_state["messages"][-1].content)

```

--------------------------------------------------------------------------------
/llm/ai-sdk/provider/types.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Type definitions for Stripe AI SDK Provider
 */

/**
 * Settings for Stripe language models
 */
export interface StripeLanguageModelSettings {
  /**
   * Stripe customer ID to associate with usage.
   * Can be overridden per-call via providerOptions.
   */
  customerId?: string;

  /**
   * Additional custom headers to include in requests
   */
  headers?: Record<string, string>;
}

/**
 * Configuration for the Stripe provider
 */
export interface StripeProviderConfig {
  /**
   * Base URL for API calls (defaults to https://llm.stripe.com)
   */
  baseURL?: string;

  /**
   * Stripe API key for authentication
   */
  apiKey?: string;

  /**
   * Default Stripe customer ID to associate with usage
   */
  customerId?: string;

  /**
   * Custom headers for requests
   */
  headers?: Record<string, string>;
}

/**
 * Provider-specific options that can be passed at call time
 */
export interface StripeProviderOptions {
  /**
   * Override customer ID for this specific call
   */
  customerId?: string;

  /**
   * Additional headers for this specific call
   */
  headers?: Record<string, string>;
}


```

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

```python
"""Stripe Agent Toolkit."""

from typing import List, Optional
from pydantic import PrivateAttr

from ..api import StripeAPI
from ..tools import tools
from ..configuration import Configuration, is_tool_allowed
from .tool import StripeTool


class StripeAgentToolkit:
    _tools: List = PrivateAttr(default=[])

    def __init__(
        self, secret_key: str, configuration: Optional[Configuration] = None
    ):
        super().__init__()

        context = configuration.get("context") if configuration else None

        stripe_api = StripeAPI(secret_key=secret_key, context=context)

        filtered_tools = [
            tool for tool in tools if is_tool_allowed(tool, configuration)
        ]

        self._tools = [
            StripeTool(
                name=tool["method"],
                description=tool["description"],
                method=tool["method"],
                stripe_api=stripe_api,
                args_schema=tool.get("args_schema", None),
            )
            for tool in filtered_tools
        ]

    def get_tools(self) -> List:
        """Get the tools in the toolkit."""
        return self._tools

```

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

```python
"""Stripe Agent Toolkit."""

from typing import List, Optional
from pydantic import PrivateAttr

from ..api import StripeAPI
from ..tools import tools
from ..configuration import Configuration, Context, is_tool_allowed
from .tool import StripeTool


class StripeAgentToolkit:
    _tools: List = PrivateAttr(default=[])

    def __init__(
        self, secret_key: str, configuration: Optional[Configuration] = None
    ):
        super().__init__()

        context = configuration.get("context") if configuration else None

        stripe_api = StripeAPI(secret_key=secret_key, context=context)

        filtered_tools = [
            tool for tool in tools if is_tool_allowed(tool, configuration)
        ]

        self._tools = [
            StripeTool(
                name=tool["method"],
                description=tool["description"],
                method=tool["method"],
                stripe_api=stripe_api,
                args_schema=tool.get("args_schema", None),
            )
            for tool in filtered_tools
        ]

    def get_tools(self) -> List:
        """Get the tools in the toolkit."""
        return self._tools

```

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

```typescript
import {StripeAgentToolkit} from '@stripe/agent-toolkit/ai-sdk';
import {openai} from '@ai-sdk/openai';
import {generateText, wrapLanguageModel, stepCountIs} from 'ai';

require('dotenv').config();

const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    actions: {
      paymentLinks: {
        create: true,
      },
      products: {
        create: true,
      },
      prices: {
        create: true,
      },
    },
  },
});

const model = wrapLanguageModel({
  model: openai('gpt-5'),
  middleware: stripeAgentToolkit.middleware({
    billing: {
      customer: process.env.STRIPE_CUSTOMER_ID!,
      meters: {
        input: process.env.STRIPE_METER_INPUT!,
        output: process.env.STRIPE_METER_OUTPUT!,
      },
    },
  }),
});

(async () => {
  const result = await generateText({
    model: model,

    tools: {
      ...stripeAgentToolkit.getTools(),
    },

    stopWhen: stepCountIs(5),

    prompt:
      '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.',
  });

  console.log(result);
})();

```

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

```python
"""Stripe Agent Toolkit."""

from typing import List, Optional, Dict
from strands.tools.tools import PythonAgentTool as StrandTool

from ..api import StripeAPI
from ..tools import tools
from ..configuration import Configuration, is_tool_allowed
from .tool import StripeTool
from .hooks import BillingHooks


class StripeAgentToolkit:
    def __init__(
        self, secret_key: str, configuration: Optional[Configuration] = None
    ):
        context = configuration.get("context") if configuration else None

        self._stripe_api = StripeAPI(secret_key=secret_key, context=context)

        filtered_tools = [
            tool for tool in tools if is_tool_allowed(tool, configuration)
        ]

        self._tools = [
            StripeTool(self._stripe_api, tool)
            for tool in filtered_tools
        ]

    def get_tools(self) -> List[StrandTool]:
        """Get the tools in the toolkit."""
        return self._tools

    def billing_hook(
        self,
        type: Optional[str] = None,
        customer: Optional[str] = None,
        meter: Optional[str] = None,
        meters: Optional[Dict[str, str]] = None
    ) -> BillingHooks:
        return BillingHooks(self._stripe_api, type, customer, meter, meters)

```

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

```typescript
import {retrieveBalance} from '@/shared/balance/retrieveBalance';

const Stripe = jest.fn().mockImplementation(() => ({
  balance: {
    retrieve: jest.fn(),
  },
}));

let stripe: ReturnType<typeof Stripe>;

beforeEach(() => {
  stripe = new Stripe('fake-api-key');
});

describe('retrieveBalance', () => {
  it('should retrieve the balance and return it', async () => {
    const mockBalance = {available: [{amount: 1000, currency: 'usd'}]};

    const context = {};

    stripe.balance.retrieve.mockResolvedValue(mockBalance);

    const result = await retrieveBalance(stripe, context, {});

    expect(stripe.balance.retrieve).toHaveBeenCalledWith({}, undefined);
    expect(result).toEqual(mockBalance);
  });

  it('should specify the connected account if included in context', async () => {
    const mockBalance = {available: [{amount: 1000, currency: 'usd'}]};

    const context = {
      account: 'acct_123456',
    };

    stripe.balance.retrieve.mockResolvedValue(mockBalance);

    const result = await retrieveBalance(stripe, context, {});

    expect(stripe.balance.retrieve).toHaveBeenCalledWith(
      {},
      {
        stripeAccount: context.account,
      }
    );
    expect(result).toEqual(mockBalance);
  });
});

```

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

```typescript
import {createPaymentLinkPrompt} from '@/shared/paymentLinks/createPaymentLink';

describe('createPaymentLinkPrompt', () => {
  it('should return the correct prompt', () => {
    const prompt = createPaymentLinkPrompt({});

    expect(prompt).toContain('This tool will create a payment link in Stripe.');
    expect(prompt).toContain(
      'price (str): The ID of the price to create the payment link for.'
    );
    expect(prompt).toContain(
      'quantity (int): The quantity of the product to include in the payment link.'
    );
    expect(prompt).toContain(
      'redirect_url (str, optional): The URL to redirect to after the payment is completed.'
    );
  });

  it('should return the correct prompt with customer context', () => {
    const prompt = createPaymentLinkPrompt({customer: 'cus_123'});

    expect(prompt).toContain('This tool will create a payment link in Stripe.');
    expect(prompt).toContain(
      'price (str): The ID of the price to create the payment link for.'
    );
    expect(prompt).toContain(
      'quantity (int): The quantity of the product to include in the payment link.'
    );
    expect(prompt).toContain(
      'redirect_url (str, optional): The URL to redirect to after the payment is completed.'
    );
  });
});

```

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

```typescript
import {StripeAgentToolkit} from '@stripe/agent-toolkit/langchain';
import {ChatOpenAI} from '@langchain/openai';
import type {ChatPromptTemplate} from '@langchain/core/prompts';
import {pull} from 'langchain/hub';
import {AgentExecutor, createStructuredChatAgent} from 'langchain/agents';

require('dotenv').config();

const llm = new ChatOpenAI({
  model: 'gpt-4o',
});

const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    actions: {
      paymentLinks: {
        create: true,
      },
      products: {
        create: true,
      },
      prices: {
        create: true,
      },
    },
  },
});

(async (): Promise<void> => {
  const prompt = await pull<ChatPromptTemplate>(
    'hwchase17/structured-chat-agent'
  );

  const tools = stripeAgentToolkit.getTools();

  const agent = await createStructuredChatAgent({
    llm,
    tools,
    prompt,
  });

  const agentExecutor = new AgentExecutor({
    agent,
    tools,
  });

  const response = await agentExecutor.invoke({
    input: `
      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.
    `,
  });

  console.log(response);
})();

```

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

```python
"""
This tool allows agents to interact with the Stripe API.
"""

from __future__ import annotations

from collections.abc import Awaitable
from typing import Any
import json

from agents import FunctionTool
from agents.run_context import RunContextWrapper

def StripeTool(api, tool) -> FunctionTool:
    async def on_invoke_tool(ctx: RunContextWrapper[Any], input_str: str) -> str:
        return api.run(tool["method"], **json.loads(input_str))

    parameters = tool["args_schema"].model_json_schema()
    parameters["additionalProperties"] = False
    parameters["type"] = "object"

    # Remove the description field from parameters as it's not needed in the OpenAI function schema
    if "description" in parameters:
        del parameters["description"]

    if "title" in parameters:
        del parameters["title"]

    # Remove title and default fields from properties
    if "properties" in parameters:
        for prop in parameters["properties"].values():
            if "title" in prop:
                del prop["title"]
            if "default" in prop:
                del prop["default"]

    return FunctionTool(
        name=tool["method"],
        description=tool["description"],
        params_json_schema=parameters,
        on_invoke_tool=on_invoke_tool,
        strict_json_schema=False
    )

```

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

```typescript
import {createProductParameters} from '@/shared/products/createProduct';
import {listProductsParameters} from '@/shared/products/listProducts';

describe('createProductParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = createProductParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['name', 'description']);
    expect(fields.length).toBe(2);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = createProductParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['name', 'description']);
    expect(fields.length).toBe(2);
  });
});

describe('listProductsParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = listProductsParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['limit']);
    expect(fields.length).toBe(1);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = listProductsParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['limit']);
    expect(fields.length).toBe(1);
  });
});

```

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

```python
"""Stripe Agent Toolkit."""

from typing import List, Optional
from pydantic import PrivateAttr
import json

from agents import FunctionTool


from ..api import StripeAPI
from ..tools import tools
from ..configuration import Configuration, is_tool_allowed
from .tool import StripeTool
from .hooks import BillingHooks

class StripeAgentToolkit:
    _tools: List[FunctionTool] = PrivateAttr(default=[])
    _stripe_api: StripeAPI = PrivateAttr(default=None)

    def __init__(
        self, secret_key: str, configuration: Optional[Configuration] = None
    ):
        super().__init__()

        context = configuration.get("context") if configuration else None

        self._stripe_api = StripeAPI(secret_key=secret_key, context=context)

        filtered_tools = [
            tool for tool in tools if is_tool_allowed(tool, configuration)
        ]

        self._tools = [
            StripeTool(self._stripe_api, tool)
            for tool in filtered_tools
        ]

    def get_tools(self) -> List[FunctionTool]:
        """Get the tools in the toolkit."""
        return self._tools

    def billing_hook(self, type: Optional[str] = None, customer: Optional[str] = None, meter: Optional[str] = None, meters: Optional[dict[str, str]] = None) -> BillingHooks:
        return BillingHooks(self._stripe_api, type, customer, meter, meters)

```

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

```typescript
import Stripe from 'stripe';
import {z} from 'zod';
import type {Context} from '@/shared/configuration';
import type {StripeToolDefinition} from '@/shared/tools';

export const retrieveBalancePrompt = (_context: Context = {}) => `
This tool will retrieve the balance from Stripe. It takes no input.
`;

export const retrieveBalanceParameters = (
  _context: Context = {}
): z.AnyZodObject => z.object({});

export const retrieveBalanceAnnotations = () => ({
  destructiveHint: false,
  idempotentHint: true,
  openWorldHint: true,
  readOnlyHint: true,
  title: 'Retrieve balance',
});

export const retrieveBalance = async (
  stripe: Stripe,
  context: Context,
  params: z.infer<ReturnType<typeof retrieveBalanceParameters>>
) => {
  try {
    const balance = await stripe.balance.retrieve(
      params,
      context.account ? {stripeAccount: context.account} : undefined
    );

    return balance;
  } catch (error) {
    return 'Failed to retrieve balance';
  }
};

const tool = (context: Context): StripeToolDefinition => ({
  method: 'retrieve_balance',
  name: 'Retrieve Balance',
  description: retrieveBalancePrompt(context),
  inputSchema: retrieveBalanceParameters(context),
  annotations: retrieveBalanceAnnotations(),
  actions: {
    balance: {
      read: true,
    },
  },
  execute: retrieveBalance,
});

export default tool;

```

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

```typescript
import {createPriceParameters} from '@/shared/prices/createPrice';
import {listPricesParameters} from '@/shared/prices/listPrices';

describe('createPriceParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = createPriceParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['product', 'unit_amount', 'currency']);
    expect(fields.length).toBe(3);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = createPriceParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['product', 'unit_amount', 'currency']);
    expect(fields.length).toBe(3);
  });
});

describe('listPricesParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = listPricesParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['product', 'limit']);
    expect(fields.length).toBe(2);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = listPricesParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['product', 'limit']);
    expect(fields.length).toBe(2);
  });
});

```

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

```typescript
import {createInvoicePrompt} from '@/shared/invoices/createInvoice';
import {listInvoicesPrompt} from '@/shared/invoices/listInvoices';
import {finalizeInvoicePrompt} from '@/shared/invoices/finalizeInvoice';

describe('createInvoicePrompt', () => {
  it('should return the correct prompt when no customer is specified', () => {
    const prompt = createInvoicePrompt({});
    expect(prompt).toContain('- customer (str)');
  });

  it('should return the correct prompt when a customer is specified', () => {
    const prompt = createInvoicePrompt({customer: 'cus_123'});
    expect(prompt).toContain('context: cus_123');
    expect(prompt).not.toContain('- customer (str)');
  });
});

describe('listInvoicesPrompt', () => {
  it('should return the correct prompt when no customer is specified', () => {
    const prompt = listInvoicesPrompt({});
    expect(prompt).toContain('- customer (str, optional)');
  });

  it('should return the correct prompt when a customer is specified', () => {
    const prompt = listInvoicesPrompt({customer: 'cus_123'});
    expect(prompt).toContain('context: cus_123');
    expect(prompt).not.toContain('- customer (str, optional)');
  });
});

describe('finalizeInvoicePrompt', () => {
  it('should return the correct prompt', () => {
    const prompt = finalizeInvoicePrompt();
    expect(prompt).toContain('invoice');
  });
});

```

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

```python
import env
from agents import Agent, Runner, function_tool, TResponseInputItem, RunResult
from stripe_agent_toolkit.openai.toolkit import StripeAgentToolkit
import requests

env.ensure("OPENAI_API_KEY")

stripe_agent_toolkit = StripeAgentToolkit(
    secret_key=env.ensure("STRIPE_SECRET_KEY"),
    configuration={
        "actions": {
            "customers": {
                "read": True,
            },
            "invoices": {
                "read": True,
            },
            "billing_portal_sessions": {
                "create": True,
            },
        }
    },
)


@function_tool
def search_faq(question: str) -> str:
    response = requests.get("https://standupjack.com/faq")
    if response.status_code != 200:
        return "Not sure"
    return f"Given the following context:\n{response.text}\n\nAnswer '{question}' or response with not sure\n"


support_agent = Agent(
    name="Standup Jack Agent",
    instructions=(
        "You are a helpful customer support assistant"
        "Be casual and concise"
        "You only respond with markdown"
        "Use tools to support customers"
        "Respond with I'm not sure to any other prompts"
        "Sign off with Standup Jack Bot"
    ),
    tools=[search_faq, *stripe_agent_toolkit.get_tools()],
)


async def run(input: list[TResponseInputItem]) -> RunResult:
    return await Runner.run(support_agent, input)

```

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

```typescript
import {StripeAgentToolkit} from '@stripe/agent-toolkit/openai';
import OpenAI from 'openai';
import type {ChatCompletionMessageParam} from 'openai/resources';

require('dotenv').config();

const openai = new OpenAI();

const stripeAgentToolkit = new StripeAgentToolkit({
  secretKey: process.env.STRIPE_SECRET_KEY!,
  configuration: {
    actions: {
      paymentLinks: {
        create: true,
      },
      products: {
        create: true,
      },
      prices: {
        create: true,
      },
    },
  },
});

(async (): Promise<void> => {
  let messages: ChatCompletionMessageParam[] = [
    {
      role: 'user',
      content: `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.`,
    },
  ];

  while (true) {
    // eslint-disable-next-line no-await-in-loop
    const completion = await openai.chat.completions.create({
      model: 'gpt-4o',
      messages,
      tools: stripeAgentToolkit.getTools(),
    });

    const message = completion.choices[0].message;

    messages.push(message);

    if (message.tool_calls) {
      // eslint-disable-next-line no-await-in-loop
      const toolMessages = await Promise.all(
        message.tool_calls.map((tc) => stripeAgentToolkit.handleToolCall(tc))
      );
      messages = [...messages, ...toolMessages];
    } else {
      console.log(completion.choices[0].message);
      break;
    }
  }
})();

```

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

```yaml
name: Python Release

on:
  workflow_dispatch: {}

jobs:
  python-build:
    name: Build for PyPi
    runs-on: ubuntu-latest
    environment: pypi
    permissions:
      contents: read

    defaults:
      run:
        working-directory: ./tools/python

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.11"

      - name: Install uv
        uses: astral-sh/setup-uv@v2

      - name: Install
        run: make venv

      - name: Build
        run: |
          set -x
          source .venv/bin/activate
          rm -rf build dist *.egg-info
          make build
          python -m twine check dist/*

      - name: Test
        run: |
          make venv
          make test

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: release-dists
          path: ./tools/python/dist/

  python-release:
    name: Publish to PyPi
    runs-on: ubuntu-latest
    environment: pypi
    needs:
      - python-build

    defaults:
      run:
        working-directory: ./tools/python

    permissions:
      id-token: write

    steps:
      - name: Retrieve distribution
        uses: actions/download-artifact@v4
        with:
          name: release-dists
          path: dist/

      - name: Publish package distributions to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1

```

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

```typescript
import {createCustomerParameters} from '@/shared/customers/createCustomer';
import {listCustomersParameters} from '@/shared/customers/listCustomers';

describe('createCustomerParameters', () => {
  it('should return the correct parameters if no context', () => {
    // Create the parameters schema with an empty context
    const parameters = createCustomerParameters({});

    // Validate that the schema has the expected keys
    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['name', 'email']);
    expect(fields.length).toBe(2);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = createCustomerParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['name', 'email']);
    expect(fields.length).toBe(2);
  });
});

describe('listCustomersParameters', () => {
  it('should return the correct parameters if no context', () => {
    const parameters = listCustomersParameters({});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['limit', 'email']);
    expect(fields.length).toBe(2);
  });

  it('should return the correct parameters if customer is specified', () => {
    const parameters = listCustomersParameters({customer: 'cus_123'});

    const fields = Object.keys(parameters.shape);
    expect(fields).toEqual(['limit', 'email']);
    expect(fields.length).toBe(2);
  });
});

```

--------------------------------------------------------------------------------
/llm/ai-sdk/tsup.config.ts:
--------------------------------------------------------------------------------

```typescript
import {defineConfig} from 'tsup';

export default defineConfig([
  // Provider build
  {
    entry: {
      'provider/index': 'provider/index.ts',
      'provider/stripe-provider': 'provider/stripe-provider.ts',
      'provider/stripe-language-model': 'provider/stripe-language-model.ts',
      'provider/utils': 'provider/utils.ts',
      'provider/types': 'provider/types.ts',
    },
    outDir: 'dist',
    format: ['cjs', 'esm'],
    dts: true,
    sourcemap: true,
    clean: true,
    splitting: false,
    external: ['@ai-sdk/provider', '@ai-sdk/provider-utils', 'stripe', 'zod'],
    platform: 'node',
    target: 'es2022',
    tsconfig: 'provider/tsconfig.build.json',
    outExtension({format}) {
      return {
        js: format === 'cjs' ? '.js' : '.mjs',
      };
    },
  },
  // Meter build
  {
    entry: {
      'meter/index': 'meter/index.ts',
      'meter/wrapperV2': 'meter/wrapperV2.ts',
      'meter/meter-event-logging': 'meter/meter-event-logging.ts',
      'meter/meter-event-types': 'meter/meter-event-types.ts',
      'meter/types': 'meter/types.ts',
      'meter/utils': 'meter/utils.ts',
    },
    outDir: 'dist',
    format: ['cjs', 'esm'],
    dts: true,
    sourcemap: true,
    splitting: false,
    external: ['@ai-sdk/provider', 'stripe'],
    platform: 'node',
    target: 'es2022',
    tsconfig: 'meter/tsconfig.json',
    outExtension({format}) {
      return {
        js: format === 'cjs' ? '.js' : '.mjs',
      };
    },
  },
]);


```

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

```python
import os
from dotenv import load_dotenv

from crewai import Agent, Task, Crew
from stripe_agent_toolkit.crewai.toolkit import StripeAgentToolkit

load_dotenv()

stripe_agent_toolkit = StripeAgentToolkit(
    secret_key=os.getenv("STRIPE_SECRET_KEY"),
    configuration={
        "actions": {
            "payment_links": {
                "create": True,
            },
            "products": {
                "create": True,
            },
            "prices": {
                "create": True,
            },
        }
    },
)

stripe_agent = Agent(
    role="Stripe Agent",
    goal="Integrate with Stripe effectively to support our business.",
    backstory="You have been using stripe forever.",
    tools=[*stripe_agent_toolkit.get_tools()],
    allow_delegation=False,
    verbose=True,
)

haiku_writer = Agent(
    role="Haiku writer",
    goal="Write a haiku",
    backstory="You are really good at writing haikus.",
    allow_delegation=False,
    verbose=True,
)

create_payment_link = Task(
    description="Create a payment link for a new product called 'test' "
    "with a price of $100. The description should be a haiku",
    expected_output="url",
    agent=stripe_agent,
)

write_haiku = Task(
    description="Write a haiku about buy bots.",
    expected_output="haiku",
    agent=haiku_writer,
)

crew = Crew(
    agents=[stripe_agent, haiku_writer],
    tasks=[create_payment_link, write_haiku],
    verbose=True,
    planning=True,
)

crew.kickoff()

```

--------------------------------------------------------------------------------
/.github/workflows/sync-skills.yml:
--------------------------------------------------------------------------------

```yaml
name: Sync MCP prompts to skills folder

on:
  # schedule:
  #   # Run daily at 00:00 UTC
  #   - cron: '0 0 * * *'
  workflow_dispatch: # Allow manual triggering

permissions:
  contents: write
  pull-requests: write

jobs:
  sync:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      
      - name: Run sync script
        env:
          MCP_STRIPE_API_KEY: ${{ secrets.MCP_STRIPE_API_KEY }}
        run: node skills/sync.js
      
      # This action will only create a PR if there are actual changes to the file
      # If the content is identical, no PR will be created
      - name: Create Pull Request
        id: cpr
        uses: peter-evans/create-pull-request@v6
        with:
          commit-message: 'sync mcp.stripe.comp prompts to skills'
          title: '[automated] sync mcp.stripe.comp prompts to skills'
          body: |
            This is an automated PR created by the sync-skills workflow.
          branch: sync-skills-update
          delete-branch: true
          add-paths: |
            skills/stripe-best-practices.md
      
      - name: Check outputs
        if: steps.cpr.outputs.pull-request-number
        run: |
          echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
          echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"


```

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

```typescript
import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';
import {RequestHandlerExtra} from '@modelcontextprotocol/sdk/shared/protocol.js';
import {Configuration, isToolAllowed} from '../shared/configuration';
import StripeAPI from '../shared/api';
import tools from '../shared/tools';

class StripeAgentToolkit extends McpServer {
  private _stripe: StripeAPI;

  constructor({
    secretKey,
    configuration,
  }: {
    secretKey: string;
    configuration: Configuration;
  }) {
    super({
      name: 'Stripe',
      version: '0.4.0',
      configuration: {
        ...configuration,
        context: {
          ...configuration.context,
          mode: 'modelcontextprotocol',
        },
      },
    });

    this._stripe = new StripeAPI(secretKey, configuration.context);

    const context = configuration.context || {};
    const filteredTools = tools(context).filter((tool) =>
      isToolAllowed(tool, configuration)
    );

    filteredTools.forEach((tool) => {
      this.tool(
        tool.method,
        tool.description,
        tool.inputSchema.shape,
        tool.annotations,
        async (arg: any, _extra: RequestHandlerExtra<any, any>) => {
          const result = await this._stripe.run(tool.method, arg);
          return {
            content: [
              {
                type: 'text' as const,
                text: String(result),
              },
            ],
          };
        }
      );
    });
  }
}

export default StripeAgentToolkit;

```

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

```typescript
import Stripe from 'stripe';

import type {Context} from './configuration';
import tools, {StripeToolDefinition} from './tools';

const TOOLKIT_HEADER = 'stripe-agent-toolkit-typescript';
const MCP_HEADER = 'stripe-mcp';

class StripeAPI {
  stripe: Stripe;

  context: Context;

  tools: StripeToolDefinition[];

  constructor(secretKey: string, context?: Context) {
    const stripeClient = new Stripe(secretKey, {
      appInfo: {
        name:
          context?.mode === 'modelcontextprotocol'
            ? MCP_HEADER
            : TOOLKIT_HEADER,
        version: '0.8.1',
        url: 'https://github.com/stripe/ai',
      },
    });
    this.stripe = stripeClient;
    this.context = context || {};
    this.tools = tools(this.context);
  }

  async createMeterEvent({
    event,
    customer,
    value,
  }: {
    event: string;
    customer: string;
    value: string;
  }) {
    await this.stripe.billing.meterEvents.create(
      {
        event_name: event,
        payload: {
          stripe_customer_id: customer,
          value: value,
        },
      },
      this.context.account ? {stripeAccount: this.context.account} : undefined
    );
  }

  async run(method: string, arg: any) {
    const tool = this.tools.find((t) => t.method === method);
    if (tool) {
      const output = JSON.stringify(
        await tool.execute(this.stripe, this.context, arg)
      );
      return output;
    } else {
      throw new Error('Invalid method ' + method);
    }
  }
}

export default StripeAPI;

```

--------------------------------------------------------------------------------
/llm/token-meter/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@stripe/token-meter",
  "version": "0.1.0",
  "description": "Generic token metering for AI SDKs with Stripe integration",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    }
  },
  "scripts": {
    "build": "tsc --project tsconfig.build.json",
    "clean": "rm -rf dist",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "prepublishOnly": "npm run build"
  },
  "keywords": [
    "stripe",
    "ai",
    "billing",
    "tokens",
    "metering"
  ],
  "author": "Stripe <[email protected]> (https://stripe.com/)",
  "license": "MIT",
  "engines": {
    "node": ">=18"
  },
  "files": [
    "dist/**/*",
    "LICENSE",
    "README.md",
    "package.json"
  ],
  "devDependencies": {
    "@anthropic-ai/sdk": "^0.67.0",
    "@google/generative-ai": "^0.24.1",
    "@types/jest": "^30.0.0",
    "@types/node": "^22.10.5",
    "dotenv": "^17.2.3",
    "jest": "^30.2.0",
    "openai": "^6.6.0",
    "ts-jest": "^29.4.5",
    "ts-node": "^10.9.2",
    "typescript": "^5.8.3"
  },
  "dependencies": {
    "stripe": "^17.5.0"
  },
  "peerDependencies": {
    "@anthropic-ai/sdk": "^0.32.1",
    "@google/generative-ai": "^0.21.0",
    "openai": "^4.86.1"
  },
  "peerDependenciesMeta": {
    "@anthropic-ai/sdk": {
      "optional": true
    },
    "@google/generative-ai": {
      "optional": true
    },
    "openai": {
      "optional": true
    }
  }
}

```

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

```python
import unittest
from stripe_agent_toolkit.configuration import is_tool_allowed


class TestConfigurations(unittest.TestCase):
    def test_allowed(self):
        tool = {
            "actions": {
                "customers": {"create": True, "read": True},
                "invoices": {"create": True, "read": True},
            }
        }

        configuration = {
            "actions": {
                "customers": {"create": True, "read": True},
                "invoices": {"create": True, "read": True},
            }
        }

        self.assertTrue(is_tool_allowed(tool, configuration))

    def test_partial_allowed(self):
        tool = {
            "actions": {
                "customers": {"create": True, "read": True},
                "invoices": {"create": True, "read": True},
            }
        }

        configuration = {
            "actions": {
                "customers": {"create": True, "read": True},
                "invoices": {"create": True, "read": False},
            }
        }

        self.assertFalse(is_tool_allowed(tool, configuration))

    def test_not_allowed(self):
        tool = {
            "actions": {
                "payment_links": {"create": True},
            }
        }

        configuration = {
            "actions": {
                "customers": {"create": True, "read": True},
                "invoices": {"create": True, "read": True},
            }
        }

        self.assertFalse(is_tool_allowed(tool, configuration))


if __name__ == "__main__":
    unittest.main()

```

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

```javascript
/* eslint-disable no-sync */
const esbuild = require('esbuild');
const fsSync = require('fs');

const dxt = require('@anthropic-ai/dxt');

// Ensure dist directory exists
if (!fsSync.existsSync('dxt-dist')) {
  fsSync.mkdirSync('dxt-dist');
}

// Build configuration
const buildConfig = {
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dxt-dist/index.js',
  platform: 'node',
  target: 'node18',
  format: 'cjs',
  external: [],
  minify: true,
  sourcemap: false,
  metafile: false,
  write: true,
  logLevel: 'info',
};

async function build() {
  try {
    console.log('🔨 Building with esbuild...');

    const result = await esbuild.build(buildConfig);

    if (result.errors.length > 0) {
      console.error('❌ Build failed with errors:');
      result.errors.forEach((error) => console.error(error));
      throw new Error('Build failed with errors');
    }

    if (result.warnings.length > 0) {
      console.warn('⚠️  Build completed with warnings:');
      result.warnings.forEach((warning) => console.warn(warning));
    }

    // Make the output file executable
    fsSync.chmodSync('dxt-dist/index.js', '755');

    console.log('✅ Build completed successfully!');
    console.log('📦 Output: dxt-dist/index.js');
  } catch (error) {
    console.error('❌ Build failed:', error);
    throw error;
  }
}

// Run the build
build();

// Pack the actual DXT extension
dxt.packExtension({
  extensionPath: '.',
  outputPath: 'stripe.dxt',
  silent: true,
});

console.log('✅ DXT extension built successfully!');
console.log('📦 Output: stripe.dxt');

```

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

```typescript
import Stripe from 'stripe';
import {z} from 'zod';
import type {Context} from '@/shared/configuration';
import type {StripeToolDefinition} from '@/shared/tools';
export const createProductPrompt = (_context: Context = {}) => `
This tool will create a product in Stripe.

It takes two arguments:
- name (str): The name of the product.
- description (str, optional): The description of the product.
`;

export const createProduct = async (
  stripe: Stripe,
  context: Context,
  params: z.infer<ReturnType<typeof createProductParameters>>
) => {
  try {
    const product = await stripe.products.create(
      params,
      context.account ? {stripeAccount: context.account} : undefined
    );

    return product;
  } catch (error) {
    return 'Failed to create product';
  }
};

export const createProductParameters = (_context: Context = {}) =>
  z.object({
    name: z.string().describe('The name of the product.'),
    description: z
      .string()
      .optional()
      .describe('The description of the product.'),
  });

export const createProductAnnotations = () => ({
  destructiveHint: false,
  idempotentHint: false,
  openWorldHint: true,
  readOnlyHint: false,
  title: 'Create product',
});

const tool = (context: Context): StripeToolDefinition => ({
  method: 'create_product',
  name: 'Create Product',
  description: createProductPrompt(context),
  inputSchema: createProductParameters(context),
  annotations: createProductAnnotations(),
  actions: {
    products: {
      create: true,
    },
  },
  execute: createProduct,
});

export default tool;

```

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

```typescript
import Stripe from 'stripe';
import {z} from 'zod';
import type {Context} from '@/shared/configuration';
import type {StripeToolDefinition} from '@/shared/tools';

export const createCustomerPrompt = (_context: Context = {}) => `
This tool will create a customer in Stripe.

It takes two arguments:
- name (str): The name of the customer.
- email (str, optional): The email of the customer.
`;

export const createCustomerParameters = (
  _context: Context = {}
): z.AnyZodObject =>
  z.object({
    name: z.string().describe('The name of the customer'),
    email: z.string().email().optional().describe('The email of the customer'),
  });

export const createCustomerAnnotations = () => ({
  destructiveHint: false,
  idempotentHint: false,
  openWorldHint: true,
  readOnlyHint: false,
  title: 'Create customer',
});

export const createCustomer = async (
  stripe: Stripe,
  context: Context,
  params: z.infer<ReturnType<typeof createCustomerParameters>>
) => {
  try {
    const customer = await stripe.customers.create(
      params,
      context.account ? {stripeAccount: context.account} : undefined
    );

    return {id: customer.id};
  } catch (error) {
    return 'Failed to create customer';
  }
};

const tool = (context: Context): StripeToolDefinition => ({
  method: 'create_customer',
  name: 'Create Customer',
  description: createCustomerPrompt(context),
  inputSchema: createCustomerParameters(context),
  annotations: createCustomerAnnotations(),
  actions: {
    customers: {
      create: true,
    },
  },
  execute: createCustomer,
});

export default tool;

```

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

```typescript
import Stripe from 'stripe';
import {z} from 'zod';
import type {Context} from '@/shared/configuration';
import type {StripeToolDefinition} from '@/shared/tools';

export const finalizeInvoiceParameters = (
  _context: Context = {}
): z.AnyZodObject =>
  z.object({
    invoice: z.string().describe('The ID of the invoice to finalize.'),
  });

export const finalizeInvoicePrompt = (_context: Context = {}) => `
This tool will finalize an invoice in Stripe.

It takes one argument:
- invoice (str): The ID of the invoice to finalize.
`;

export const finalizeInvoice = async (
  stripe: Stripe,
  context: Context,
  params: z.infer<ReturnType<typeof finalizeInvoiceParameters>>
) => {
  try {
    const invoice = await stripe.invoices.finalizeInvoice(
      params.invoice,
      context.account ? {stripeAccount: context.account} : undefined
    );

    return {
      id: invoice.id,
      url: invoice.hosted_invoice_url,
      customer: invoice.customer,
      status: invoice.status,
    };
  } catch (error) {
    return 'Failed to finalize invoice';
  }
};

export const finalizeInvoiceAnnotations = () => ({
  destructiveHint: false,
  idempotentHint: true,
  openWorldHint: true,
  readOnlyHint: false,
  title: 'Finalize invoice',
});

const tool = (context: Context): StripeToolDefinition => ({
  method: 'finalize_invoice',
  name: 'Finalize Invoice',
  description: finalizeInvoicePrompt(context),
  inputSchema: finalizeInvoiceParameters(context),
  annotations: finalizeInvoiceAnnotations(),
  actions: {
    invoices: {
      update: true,
    },
  },
  execute: finalizeInvoice,
});

export default tool;

```

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

```typescript
import Stripe from 'stripe';
import {z} from 'zod';
import type {Context} from '@/shared/configuration';
import type {StripeToolDefinition} from '@/shared/tools';

export const listProductsPrompt = (_context: Context = {}) => `
This tool will fetch a list of Products from Stripe.

It takes one optional argument:
- limit (int, optional): The number of products to return.
`;

export const listProducts = async (
  stripe: Stripe,
  context: Context,
  params: z.infer<ReturnType<typeof listProductsParameters>>
) => {
  try {
    const products = await stripe.products.list(
      params,
      context.account ? {stripeAccount: context.account} : undefined
    );

    return products.data;
  } catch (error) {
    return 'Failed to list products';
  }
};

export const listProductsParameters = (
  _context: Context = {}
): z.AnyZodObject =>
  z.object({
    limit: z
      .number()
      .int()
      .min(1)
      .max(100)
      .optional()
      .describe(
        'A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.'
      ),
  });

export const listProductsAnnotations = () => ({
  destructiveHint: false,
  idempotentHint: true,
  openWorldHint: true,
  readOnlyHint: true,
  title: 'List products',
});

const tool = (context: Context): StripeToolDefinition => ({
  method: 'list_products',
  name: 'List Products',
  description: listProductsPrompt(context),
  inputSchema: listProductsParameters(context),
  annotations: listProductsAnnotations(),
  actions: {
    products: {
      read: true,
    },
  },
  execute: listProducts,
});

export default tool;

```

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

```python
from typing import Literal, Optional
from typing_extensions import TypedDict

# Define Object type
Object = Literal[
    "customers",
    "invoices",
    "invoiceItems",
    "paymentLinks",
    "products",
    "prices",
    "balance",
    "refunds",
    "paymentIntents",
]


# Define Permission type
class Permission(TypedDict, total=False):
    create: Optional[bool]
    update: Optional[bool]
    read: Optional[bool]


# Define BalancePermission type
class BalancePermission(TypedDict, total=False):
    read: Optional[bool]


# Define Actions type
class Actions(TypedDict, total=False):
    customers: Optional[Permission]
    invoices: Optional[Permission]
    invoice_items: Optional[Permission]
    payment_links: Optional[Permission]
    products: Optional[Permission]
    prices: Optional[Permission]
    balance: Optional[BalancePermission]
    refunds: Optional[Permission]
    payment_intents: Optional[Permission]
    billing_portal_sessions: Optional[Permission]


# Define Context type
class Context(TypedDict, total=False):
    account: Optional[str]


# Define Configuration type
class Configuration(TypedDict, total=False):
    actions: Optional[Actions]
    context: Optional[Context]


def is_tool_allowed(tool, configuration):
    for resource, permissions in tool.get("actions", {}).items():
        if resource not in configuration.get("actions", {}):
            return False
        for permission in permissions:
            if (
                not configuration["actions"]
                .get(resource, {})
                .get(permission, False)
            ):
                return False
    return True

```

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

```typescript
import {z, ZodRawShape} from 'zod';
import {ToolCallback} from '@modelcontextprotocol/sdk/server/mcp.js';
import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';
import {registerPaidTool} from '../modelcontextprotocol/register-paid-tool';
import type {PaidToolOptions} from '../modelcontextprotocol/register-paid-tool';

// @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'.
import {McpAgent} from 'agents/mcp';

type Env = any;

type StripeState = {
  customerId: string;
};

export type PaymentState = {
  stripe?: StripeState;
};

export type PaymentProps = {
  userEmail: string;
};

// eslint-disable-next-line @typescript-eslint/naming-convention
export abstract class experimental_PaidMcpAgent<
  Bindings extends Env,
  State extends PaymentState,
  Props extends PaymentProps,
> extends McpAgent<Bindings, State, Props> {
  paidTool<Args extends ZodRawShape>(
    toolName: string,
    toolDescription: string,
    paramsSchema: Args,
    // @ts-ignore
    paidCallback: ToolCallback<Args>,
    options: Omit<PaidToolOptions, 'userEmail' | 'stripeSecretKey'>
  ) {
    const mcpServer: McpServer = this.server as unknown as McpServer;

    const userEmail = this.props.userEmail;

    const updatedOptions = {
      ...options,
      userEmail,
      // @ts-ignore
      stripeSecretKey: this.env.STRIPE_SECRET_KEY,
    };

    // @ts-ignore
    registerPaidTool(
      mcpServer,
      toolName,
      toolDescription,
      paramsSchema,
      paidCallback,
      updatedOptions
    );
  }
}

```

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

```typescript
import Stripe from 'stripe';
import {z} from 'zod';
import type {Context} from '@/shared/configuration';
import type {StripeToolDefinition} from '@/shared/tools';

export const cancelSubscription = async (
  stripe: Stripe,
  context: Context,
  params: z.infer<ReturnType<typeof cancelSubscriptionParameters>>
) => {
  try {
    const {subscription: subscriptionId, ...cancelParams} = params;

    const subscription = await stripe.subscriptions.cancel(
      subscriptionId,
      cancelParams,
      context.account ? {stripeAccount: context.account} : undefined
    );

    return subscription;
  } catch (error) {
    return 'Failed to cancel subscription';
  }
};

export const cancelSubscriptionParameters = (
  _context: Context = {}
): z.AnyZodObject => {
  return z.object({
    subscription: z.string().describe('The ID of the subscription to cancel.'),
  });
};
export const cancelSubscriptionPrompt = (_context: Context = {}): string => {
  return `
This tool will cancel a subscription in Stripe.

It takes the following arguments:
- subscription (str, required): The ID of the subscription to cancel.
`;
};

export const cancelSubscriptionAnnotations = () => ({
  destructiveHint: true,
  idempotentHint: true,
  openWorldHint: true,
  readOnlyHint: false,
  title: 'Cancel subscription',
});

const tool = (context: Context): StripeToolDefinition => ({
  method: 'cancel_subscription',
  name: 'Cancel Subscription',
  description: cancelSubscriptionPrompt(context),
  inputSchema: cancelSubscriptionParameters(context),
  annotations: cancelSubscriptionAnnotations(),
  actions: {
    subscriptions: {
      update: true,
    },
  },
  execute: cancelSubscription,
});

export default tool;

```

--------------------------------------------------------------------------------
/llm/ai-sdk/meter/utils.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Utility functions for AI SDK metering
 */

import type {LanguageModelV2StreamPart} from '@ai-sdk/provider';
import type {Provider} from './meter-event-types';

/**
 * Determines the provider type from a given model provider string.
 * Normalizes common provider names for consistency in Stripe meter events.
 * 
 * For unknown providers, returns the lowercased provider string as-is.
 */
export function determineProvider(providerString: string): Provider {
  const normalized = providerString.toLowerCase();

  // Normalize common provider names for consistency
  if (normalized.includes('azure')) return 'azure';
  if (normalized.includes('amazon_bedrock') || normalized.includes('bedrock'))
    return 'bedrock';
  if (normalized.includes('huggingface')) return 'huggingface';
  if (normalized.includes('together')) return 'together';
  if (normalized.includes('anthropic')) return 'anthropic';
  if (normalized.includes('google') || normalized.includes('gemini'))
    return 'google';
  if (normalized.includes('groq')) return 'groq';
  if (normalized.includes('openai')) return 'openai';

  // For any other provider, return the lowercased provider name
  return normalized;
}

/**
 * Processes stream chunks to extract usage information
 */
export function extractUsageFromStream(
  chunks: LanguageModelV2StreamPart[]
): {inputTokens: number; outputTokens: number} {
  let inputTokens = 0;
  let outputTokens = 0;

  for (const chunk of chunks) {
    if (chunk.type === 'finish' && chunk.usage) {
      inputTokens = chunk.usage.inputTokens ?? 0;
      outputTokens = chunk.usage.outputTokens ?? 0;
      break; // Usage is typically in the final chunk
    }
  }

  return {inputTokens, outputTokens};
}


```

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

```typescript
import {createRefund} from '@/shared/refunds/createRefund';

const Stripe = jest.fn().mockImplementation(() => ({
  refunds: {
    create: jest.fn(),
  },
}));

let stripe: ReturnType<typeof Stripe>;

beforeEach(() => {
  stripe = new Stripe('fake-api-key');
});

describe('createRefund', () => {
  it('should create a refund and return it', async () => {
    const params = {
      payment_intent: 'pi_123456',
    };

    const mockRefund = {id: 're_123456'};

    const context = {};

    stripe.refunds.create.mockResolvedValue(mockRefund);

    const result = await createRefund(stripe, context, params);

    expect(stripe.refunds.create).toHaveBeenCalledWith(params, undefined);
    expect(result).toEqual(mockRefund);
  });

  it('should create a partial refund and return it', async () => {
    const params = {
      payment_intent: 'pi_123456',
      amount: 500,
    };

    const mockRefund = {id: 're_123456'};

    const context = {};

    stripe.refunds.create.mockResolvedValue(mockRefund);

    const result = await createRefund(stripe, context, params);

    expect(stripe.refunds.create).toHaveBeenCalledWith(params, undefined);
    expect(result).toEqual(mockRefund);
  });

  it('should specify the connected account if included in context', async () => {
    const params = {
      payment_intent: 'pi_123456',
    };

    const mockRefund = {id: 're_123456'};

    const context = {
      account: 'acct_123456',
    };

    stripe.refunds.create.mockResolvedValue(mockRefund);

    const result = await createRefund(stripe, context, params);

    expect(stripe.refunds.create).toHaveBeenCalledWith(params, {
      stripeAccount: context.account,
    });
    expect(result).toEqual(mockRefund);
  });
});

```

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

```typescript
import Stripe from 'stripe';
import {z} from 'zod';
import type {Context} from '@/shared/configuration';
import type {StripeToolDefinition} from '@/shared/tools';

export const listCouponsPrompt = (_context: Context = {}) => `
This tool will fetch a list of Coupons from Stripe.

It takes one optional argument:
- limit (int, optional): The number of coupons to return.
`;

export const listCouponsParameters = (_context: Context = {}) =>
  z.object({
    limit: z
      .number()
      .int()
      .min(1)
      .max(100)
      .optional()
      .describe(
        'A limit on the number of objects to be returned. Limit can range between 1 and 100.'
      ),
  });

export const listCouponsAnnotations = () => ({
  destructiveHint: false,
  idempotentHint: true,
  openWorldHint: true,
  readOnlyHint: true,
  title: 'List coupons',
});

export const listCoupons = async (
  stripe: Stripe,
  context: Context,
  params: z.infer<ReturnType<typeof listCouponsParameters>>
) => {
  try {
    const coupons = await stripe.coupons.list(
      params,
      context.account ? {stripeAccount: context.account} : undefined
    );

    return coupons.data.map((coupon) => ({
      id: coupon.id,
      name: coupon.name,
      percent_off: coupon.percent_off,
      amount_off: coupon.amount_off,
      duration: coupon.duration,
    }));
  } catch (error) {
    return 'Failed to list coupons';
  }
};

const tool = (context: Context): StripeToolDefinition => ({
  method: 'list_coupons',
  name: 'List Coupons',
  description: listCouponsPrompt(context),
  inputSchema: listCouponsParameters(context),
  annotations: listCouponsAnnotations(),
  actions: {
    coupons: {
      read: true,
    },
  },
  execute: listCoupons,
});

export default tool;

```

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

```typescript
import Stripe from 'stripe';
import {z} from 'zod';
import type {Context} from '@/shared/configuration';
import type {StripeToolDefinition} from '@/shared/tools';

export const listPrices = async (
  stripe: Stripe,
  context: Context,
  params: z.infer<ReturnType<typeof listPricesParameters>>
) => {
  try {
    const prices = await stripe.prices.list(
      params,
      context.account ? {stripeAccount: context.account} : undefined
    );

    return prices.data;
  } catch (error) {
    return 'Failed to list prices';
  }
};

export const listPricesParameters = (_context: Context = {}): z.AnyZodObject =>
  z.object({
    product: z
      .string()
      .optional()
      .describe('The ID of the product to list prices for.'),
    limit: z
      .number()
      .int()
      .min(1)
      .max(100)
      .optional()
      .describe(
        'A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.'
      ),
  });

export const listPricesAnnotations = () => ({
  destructiveHint: false,
  idempotentHint: true,
  openWorldHint: true,
  readOnlyHint: true,
  title: 'List prices',
});

export const listPricesPrompt = (_context: Context = {}) => `
This tool will fetch a list of Prices from Stripe.

It takes two arguments.
- product (str, optional): The ID of the product to list prices for.
- limit (int, optional): The number of prices to return.
`;

const tool = (context: Context): StripeToolDefinition => ({
  method: 'list_prices',
  name: 'List Prices',
  description: listPricesPrompt(context),
  inputSchema: listPricesParameters(context),
  annotations: listPricesAnnotations(),
  actions: {
    prices: {
      read: true,
    },
  },
  execute: listPrices,
});

export default tool;

```

--------------------------------------------------------------------------------
/skills/sync.js:
--------------------------------------------------------------------------------

```javascript
const fs = require("fs").promises;
const path = require("path");

const STRIPE_API_KEY = process.env.MCP_STRIPE_API_KEY;

if (!STRIPE_API_KEY) {
  throw new Error("MCP_STRIPE_API_KEY environment variable is required");
}

const getMCPPrompt = async (promptName) => {
  const response = await fetch("https://mcp.stripe.com", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${STRIPE_API_KEY}`,
      "User-Agent": "github.com/stripe/ai/skills",
    },
    body: JSON.stringify({
      jsonrpc: "2.0",
      method: "prompts/get",
      params: {
        name: "stripe-best-practices",
        arguments: {},
      },
      id: 1,
    }),
  });
  const data = await response.json();
  return data.result.messages[0].content.text;
};

const listMCPPrompts = async () => {
  const response = await fetch("https://mcp.stripe.com", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${STRIPE_API_KEY}`,
      "User-Agent": "github.com/stripe/ai/skills",
    },
    body: JSON.stringify({
      jsonrpc: "2.0",
      method: "prompts/list",
      params: {},
      id: 1,
    }),
  });
  const data = await response.json();
  return data.result.prompts;
};

const run = async () => {
  const prompts = await listMCPPrompts();
  console.log(`Found ${prompts.length} prompts`);
  for (const prompt of prompts) {
    const content = await getMCPPrompt(prompt.name);
    const outputPath = path.join(__dirname, `${prompt.name}.md`);

    const skillFileContent = `---
description: ${prompt.description}
alwaysApply: false
---

${content}
`;

    await fs.writeFile(outputPath, skillFileContent, "utf8");
    console.log(`Content written to ${outputPath}`);
  }
};

run();

```

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

```python
from strands.tools.tools import PythonAgentTool as StrandTool
import json

def StripeTool(api, tool) -> StrandTool:
    parameters = tool["args_schema"].model_json_schema()
    parameters["additionalProperties"] = False
    parameters["type"] = "object"

    def callback_wrapper(tool_input, **kwargs):
        """Wrapper to handle additional parameters from strands framework."""

        # Extract toolUseId for the response
        tool_use_id = None
        if isinstance(tool_input, dict) and 'toolUseId' in tool_input:
            tool_use_id = tool_input['toolUseId']
            # Extract the actual parameters from the nested input structure
            actual_params = tool_input.get('input', {})
        elif isinstance(tool_input, str):
            # Parse JSON string input
            try:
                parsed = json.loads(tool_input)
                tool_use_id = parsed.get('toolUseId')
                actual_params = parsed.get('input', parsed)
            except json.JSONDecodeError:
                actual_params = {}
        elif isinstance(tool_input, dict):
            actual_params = tool_input.copy()
        else:
            actual_params = {}

        # Call the Stripe API
        result = api.run(tool["method"], **actual_params)

        # Return in the format expected by strands
        response = {
            "content": [{"text": result}]
        }

        if tool_use_id:
            response["toolUseId"] = tool_use_id

        return response

    return StrandTool(
        tool_name=tool["method"],
        tool_spec={
            "name": tool["method"],
            "description": tool["description"],
            "inputSchema": {
                "json": parameters
            }
        },
        callback=callback_wrapper
    )

```

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

```typescript
import Stripe from 'stripe';
import {z} from 'zod';
import type {Context} from '@/shared/configuration';
import type {StripeToolDefinition} from '@/shared/tools';

export const createRefundPrompt = (_context: Context = {}) => `
This tool will refund a payment intent in Stripe.

It takes three arguments:
- payment_intent (str): The ID of the payment intent to refund.
- amount (int, optional): The amount to refund in cents.
- reason (str, optional): The reason for the refund.
`;

export const createRefund = async (
  stripe: Stripe,
  context: Context,
  params: z.infer<ReturnType<typeof createRefundParameters>>
) => {
  try {
    const refund = await stripe.refunds.create(
      params,
      context.account ? {stripeAccount: context.account} : undefined
    );

    return {
      id: refund.id,
      status: refund.status,
      amount: refund.amount,
    };
  } catch (error) {
    return 'Failed to create refund';
  }
};

export const createRefundParameters = (
  _context: Context = {}
): z.AnyZodObject =>
  z.object({
    payment_intent: z
      .string()
      .describe('The ID of the PaymentIntent to refund.'),
    amount: z
      .number()
      .int()
      .optional()
      .describe('The amount to refund in cents.'),
  });

export const createRefundAnnotations = () => ({
  destructiveHint: false,
  idempotentHint: false,
  openWorldHint: true,
  readOnlyHint: false,
  title: 'Create refund',
});

const tool = (context: Context): StripeToolDefinition => ({
  method: 'create_refund',
  name: 'Create Refund',
  description: createRefundPrompt(context),
  inputSchema: createRefundParameters(context),
  annotations: createRefundAnnotations(),
  actions: {
    refunds: {
      create: true,
    },
  },
  execute: createRefund,
});

export default tool;

```

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

```json
{
  "dxt_version": "0.1",
  "name": "@stripe/mcp",
  "display_name": "Stripe",
  "version": "0.1.0",
  "description": "Manage resources in your Stripe account and search the Stripe knowledge base.",
  "author": {
    "name": "Stripe",
    "email": "[email protected]"
  },
  "documentation": "https://docs.stripe.com/mcp",
  "user_config": {
    "stripe_secret_key": {
      "type": "string",
      "title": "Stripe key",
      "description": "Your Stripe API key. We recommend using a restricted access key.",
      "multiple": false,
      "required": true
    }
  },
  "server": {
    "type": "node",
    "entry_point": "dxt-dist/index.js",
    "mcp_config": {
      "command": "node",
      "args": ["${__dirname}/dxt-dist/index.js", "--tools=all"],
      "env": {
        "STRIPE_SECRET_KEY": "${user_config.stripe_secret_key}"
      }
    }
  },
  "tools": [
    {"name": "search_documentation"},
    {"name": "get_stripe_account_in"},
    {"name": "create_customer"},
    {"name": "list_customers"},
    {"name": "create_product"},
    {"name": "list_products"},
    {"name": "create_price"},
    {"name": "list_prices"},
    {"name": "create_payment_link"},
    {"name": "create_invoice"},
    {"name": "list_invoices"},
    {"name": "create_invoice_item"},
    {"name": "finalize_invoice"},
    {"name": "retrieve_balance"},
    {"name": "create_refund"},
    {"name": "list_payment_intents"},
    {"name": "list_subscriptions"},
    {"name": "cancel_subscription"},
    {"name": "update_subscription"},
    {"name": "list_coupons"},
    {"name": "create_coupon"},
    {"name": "update_dispute"},
    {"name": "list_disputes"}
  ],
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/stripe/ai/tree/main"
  },
  "icon": "stripe_icon.png"
}

```
Page 1/5FirstPrevNextLast