Tutorials

Build a Typed Stripe API Client from Its OpenAPI Spec

Stripe publishes its full OpenAPI spec at stripe/openapi, the same description that generates Stripe's own official SDKs. You can generate a typed client from it directly. Stripe already ships official, actively maintained SDKs for Node, Python, Ruby, Go, Java, .NET, and PHP — so this is not about replacing stripe-node. It's for a language Stripe doesn't cover, an internal wrapper, or generating typed tool calls for an agent.

Where the spec lives

Fact Value
Repo stripe/openapi
File openapi/spec3.yaml (or spec3.json)
Spec version OpenAPI 3.0.0
Size ~6.4 MB (YAML) / ~8 MB (JSON)
License Not separately stated for the spec; repo is public
Also ships spec3.sdk.yaml — an SDK-flavored variant with extra x-stripe extensions Stripe's own generator consumes

Use spec3.yaml, not spec3.sdk.yaml, unless you specifically want the internal extensions Stripe's codegen reads — most third-party generators don't understand x-stripe-* fields and will ignore them harmlessly, but the plain spec3.yaml is the cleaner public-facing target.

How to fetch it

curl -sL -o stripe-openapi.yaml \
  https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.yaml

Note the default branch is master, not main.

The honest complication: heavy anyOf/oneOf polymorphism

Stripe's spec is a real-world stress test for anyOf/oneOf handling. Scanning spec3.yaml directly:

grep -c "anyOf:" stripe-openapi.yaml   # 2051
grep -c "oneOf:"  stripe-openapi.yaml   # 317

That's over 2,300 polymorphic schema sites. Most come from Stripe's expandable fields pattern — a property like customer on a PaymentIntent can be either a string ID or a full expanded Customer object, modeled as anyOf: [string, Customer], repeated across dozens of resources. Generators vary widely in how they handle this:

  • Some produce clean discriminated unions (ideal).
  • Others produce a generic object or any-typed field, silently losing the type information.
  • A few generate a wrapper type per anyOf site, which balloons the package's type surface.

Before committing to a generator, generate a small sample against just the PaymentIntent or Customer schema and check what the expandable fields turn into. This is the single biggest quality signal for a generated Stripe client.

Generate a TypeScript client locally

npx @openapitools/openapi-generator-cli generate \
  -i stripe-openapi.yaml \
  -g typescript-fetch \
  -o ./generated/stripe-client

Given the anyOf density, it's worth also testing typescript-axios, since generator templates diverge most in exactly this area. Compare the generated types for PaymentIntent.customer between the two before picking one. For a broader walkthrough of picking a generator and judging output quality, see Generate a TypeScript SDK from OpenAPI.

The hosted path

Sourced takes the Stripe OpenAPI spec directly — paste the raw spec3.yaml URL or connect your repo — and produces hosted docs, a TypeScript SDK preview, a Python SDK preview, and an llms.txt file in one pass, with the anyOf/oneOf handling already resolved by the generation pipeline rather than something you tune generator flags for. Previews are free and unlimited, with up to two hosted noindex docs sites and one hosted MCP server, no credit card required.

When this actually makes sense

  • Learning the pattern on a spec that's genuinely hard. Stripe's anyOf density makes it a good stress test before you point a generator at your own polymorphic schemas.
  • A language Stripe doesn't officially cover — Stripe's official SDK list is broad (Node, Python, Ruby, Go, Java, .NET, PHP) but doesn't include every language; Rust, Kotlin, and others are common gaps.
  • Internal wrappers that need Stripe's types without stripe-node's specific API surface — for example, a typed proxy layer in a monorepo with its own auth handling.
  • Agent tooling. A generated Stripe client (or an MCP server built from the spec) gives an LLM agent typed, discoverable tool calls against Stripe's API.

If you're writing a Node, Python, Ruby, Go, Java, .NET, or PHP app that talks to Stripe, use the official stripe package for that language. It's maintained by Stripe, it handles idempotency keys and webhook signature verification correctly, and it tracks API version changes for you — a generated client won't replicate that by default.

FAQ

Does Stripe have an official OpenAPI spec?

Yes. stripe/openapi is Stripe's own public repository and is the same description used to generate Stripe's official SDKs — it's not a third-party reconstruction.

Is the Stripe OpenAPI spec OpenAPI 3.0 or 3.1?

3.0.0. If you need a 3.1 spec for tooling that requires JSON Schema 2020-12, you'll need to upgrade it yourself — see OpenAPI 3.1 vs 3.0 for the conversion steps.

What is spec3.sdk.yaml and should I use it instead?

spec3.sdk.yaml is a variant with extra x-stripe-* vendor extensions that Stripe's own internal generator reads. Most third-party generators ignore these extensions safely, but spec3.yaml is the cleaner, generator-agnostic choice unless you're building tooling that specifically understands Stripe's extensions.

Why does the generated client's customer field show up as any or a generic object?

That's the expandable-fields pattern (anyOf: [string, Customer]) tripping up your generator's anyOf handling. Try a different generator template (typescript-axios vs typescript-fetch), or check whether the tool supports discriminated unions before you commit to using it broadly.

Should I use a generated client instead of stripe-node?

No, not for a typical Node/TS integration — stripe-node is official, handles idempotency and webhook verification correctly, and tracks Stripe's API versioning. Generate a client only for languages Stripe doesn't cover, internal wrappers, or agent tooling.

Can Sourced host docs from the Stripe spec even if I don't need a generated SDK?

Yes — the docs and SDK generation are independent outputs of the same pipeline. You can generate hosted docs from the Stripe spec alone, free and unlimited in preview, without publishing an SDK at all.