Library / SDK
stripe/stripe-node avatar
stripe/stripe-node

stripe-node: the official Stripe API client for server-side JavaScript

Node.js library for the Stripe API.

4,521 stars939 forksTypeScriptMIT

At a glance

What is it?
stripe-node is Stripe's own Node.js wrapper around the Stripe API, generated from Stripe's OpenAPI spec and published as the stripe package on npm. It is the right default for server-side payment code in Node 18 or later, and the wrong tool for anything running in a browser.
Who is it for?
Adopt stripe-node for any server-side Node 18+ service that talks to the Stripe API, especially a TypeScript codebase that can track the latest API version. Do not adopt it for browser code; the README points at Stripe.js for collecting customer and payment information in the browser.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What stripe-node is for, and who should reach for it

The package on npm is called stripe. Its package.json describes it as a "Stripe API wrapper", and the README frames it as convenient access to the Stripe API from applications written in server-side JavaScript. That server-side qualifier is the whole scope. If you are collecting card details in a page, the README sends you to Stripe.js instead, and stripe-node is not a substitute for it.

The audience is narrow and specific: backend developers writing Node.js services that create charges, manage customers, handle subscriptions, or verify webhooks. The repository ships TypeScript source under src/ and compiles to both CJS and ESM outputs, so the same package serves a CommonJS Express server and an ESM service without a separate build. Node 18 is the floor, set in the engines field of package.json and repeated in the README's requirement section.

What it saves you is not the HTTP call. It is the surface area: typed request parameters, typed responses, pagination, error classes, and webhook signature verification, all kept in step with Stripe's API by code generation rather than hand editing. The repository carries an OPENAPI_VERSION file and a CODEGEN_VERSION file at the top level, which tells you the client is produced from the spec, not written by hand.

How the client is generated and what the types actually promise

The README is unusually candid about a versioning decision that will surprise people coming from other SDKs. The TypeScript types in stripe-node always reflect the latest shape of the Stripe API. They do not reflect the API version your account happens to be pinned to. If those two drift apart, the compiler is describing a different API than the one your requests will hit.

Stripe's stated position is that a new API version arrives when the API changes in a backwards-incompatible way, and a new major version of stripe-node ships alongside it. But the README also names a second category: changes that weaken the TypeScript types without breaking anything at runtime. Adding a value to a response enum is the example given. Because the new value is only returned when a new parameter is supplied, existing callers cannot break, so Stripe does not treat it as a breaking change and does not cut a major release for it. The practical consequence is that upgrading a minor version can produce new type errors, which you resolve with additional type guards. Stripe says it weighed this against outdated types or far more frequent majors, and chose this one.

Open enums are handled by widening the type. Rather than a closed union of literal values, open enum fields include a string type via OtherString, so a value Stripe adds after your SDK release still type-checks. That is a deliberate trade: you get forward compatibility on responses, and you lose exhaustiveness checking on those fields.

Installing stripe and making a first real call

The README gives two install commands, one for npm and one for yarn. Either produces the same package.

bash
npm install stripe
# or
yarn add stripe

You then need a secret key from the Stripe Dashboard. The README's first example constructs the client with a test key and creates a customer, printing the returned id.

js
import Stripe from 'stripe';
const stripeClient = new Stripe('sk_test_...');

const customer = await stripeClient.customers.create({
  email: '[email protected]',
});

console.log(customer.id);

The CJS form is different in one way that trips people up: the default export is called as a function, not with new. The README shows Stripe('sk_test_...') rather than new Stripe(...).

js
const Stripe = require('stripe');
const stripeClient = Stripe('sk_test_...');

stripeClient.customers
  .create({
    email: '[email protected]',
  })
  .then((customer) => console.log(customer.id))
  .catch((error) => console.error(error));

On the TypeScript side, the README is explicit that you import Stripe as a default import, not as * as Stripe, which differs from the DefinitelyTyped version. It also recommends annotating parameters with the exported param types.

ts
import Stripe from 'stripe';
const stripeClient = new Stripe('sk_test_...');

const params: Stripe.CustomerCreateParams = {
  description: 'test customer',
};

const customer: Stripe.Customer = await stripeClient.customers.create(params);

One caveat the README raises itself: if you are on v17.x.x or later and get a missing API key error even though the key is set, the likely cause is that the module instantiates Stripe at import time while the key is absent, for instance during a build step. The suggested fixes are lazy instantiation behind a getter, or a placeholder fallback key.

Expandable fields and the cast you will write more than once

The expand parameter is where the type system stops helping and starts asking you to assert. Expandable fields are typed as string | Foo, because the API returns an id unless you asked for the object. The README's own example retrieves a PaymentIntent with expand: ['customer'] and then casts the result to Stripe.Customer to read the email.

ts
const paymentIntent: Stripe.PaymentIntent = await stripeClient.paymentIntents.retrieve(
  'pi_123456789',
  {
    expand: ['customer'],
  }
);
const customerEmail: string = (paymentIntent.customer as Stripe.Customer).email;

That cast is unchecked. If the expand parameter is dropped from the call, or the field comes back as a string for any reason, the cast still compiles and the property access fails at runtime. The README offers a getId helper for the common case of needing only the id, which is the safer pattern when you do not actually need the nested object. This is a real cost of modelling expandable fields honestly rather than typing everything as Foo and lying to you.

Where stripe-node is the wrong choice

The clearest boundary is the browser. The README states plainly that for collecting customer and payment information in the browser you should use Stripe.js. Shipping a secret key into client-side code is not a configuration problem stripe-node can solve, and the SDK is not built for that environment.

The second boundary is API version drift. If your account is pinned to an older API version such as 2019-10-17 and you cannot upgrade, the README acknowledges the mismatch. The types only reflect the latest version, so you are told to pass the older version explicitly and silence type errors with a comment like // @ts-ignore stripe-version-2019-10-17, then remove those comments when you upgrade. That is a workable escape hatch, but it means the type safety you came for is switched off precisely where your code diverges from the current API. If you cannot upgrade your API version and you rely on the compiler to catch mistakes, this SDK gives you less than its README's opening promise suggests.

Third, the package has no runtime dependencies at all; the dependencies field in package.json is empty, with @types/node as an optional peer dependency. That is good for install size, but it means retry behaviour, connection pooling and HTTP tuning are not something you configure through a bundled client. Whatever the underlying transport does is what you get.

How it compares to calling the Stripe API directly

The alternative to stripe-node is not usually another Node SDK. It is fetch or axios against https://api.stripe.com with your own wrapper. The difference in approach is who owns the schema. With stripe-node, Stripe's codegen pipeline owns it: the repository pins an OpenAPI version and a codegen version, and the published types move when the API moves, on Stripe's release cadence. With a hand-rolled client, you own the schema, which means you also own every field rename, every new enum value, and every pagination edge case, and you find out about them from failed requests rather than from the compiler.

That trade cuts both ways. A hand-rolled client lets you pin exactly the API version you target and type only the fields you use, so a minor stripe-node upgrade cannot introduce type errors in code you never touch. It also lets you keep the transport behaviour you already tuned. What you give up is webhook signature verification, the error class hierarchy, and the generated param types, all of which you would then reimplement and test yourself. For a service that touches three endpoints, that may be a fair trade. For one that touches thirty, it is not.

Licence, release cadence and the cost of staying current

stripe-node is MIT licensed, stated in package.json and in the LICENSE file at the repository root. That is permissive: you can use it in closed-source commercial software, and the licence text imposes no obligation beyond keeping the notice. It says nothing about your agreement with Stripe as a payment processor, which is a separate contract and outside what a repository licence can tell you.

The upgrade cost is the thing to budget for, and the README is the best source on it. Because types track the latest API version, minor upgrades can surface new type errors from widened enums, and major upgrades follow Stripe API versions that change in backwards-incompatible ways. The repository also publishes alpha releases alongside stable ones; the recent release list shows v22.7.0-alpha.4 and v22.7.0-alpha.3 alongside v22.6.2, so the alpha channel is active and should not be what your production service resolves to.

On maintenance, the last push to the default branch was on 2026-09-23, and the repository is not archived. Beyond that, the repository does not document a support window per major version, so the versioning policy page linked from the README is where the schedule lives.

Editorial conclusion

Adopt stripe-node for any server-side Node 18+ service that talks to the Stripe API, especially a TypeScript codebase that can track the latest API version. Do not adopt it for browser code; the README points at Stripe.js for collecting customer and payment information in the browser. Before writing code, check the pinned API version in your Stripe Dashboard against the one your stripe-node major version targets, and confirm whether you need the lazy client instantiation pattern if your build step imports the module before environment variables exist.

Frequently asked questions

What is stripe-node used for?

It provides access to the Stripe API from server-side JavaScript applications, so backend services can create customers, take payments and manage Stripe resources. The README positions it strictly for server-side use and points browser code at Stripe.js.

Is stripe-node an SDK?

Yes. package.json describes the stripe package as a "Stripe API wrapper", and the README calls it the Stripe Node library, generated from Stripe's OpenAPI spec and published on npm.

What is the Stripe API used for in stripe-node?

The SDK wraps the Stripe API so Node services can call it with typed parameters and responses. The README's first example uses it to create a customer and read back the generated id.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. stripe/stripe-node on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/stripe-stripe-node.svg)](https://hysenlabs.com/projects/stripe-stripe-node)