npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

brex

v2.0.0

Published

Unofficial TypeScript SDK for the Brex API, generated deterministically from Brex's OpenAPI specs. Tree-shakeable, ESM-only, zero dependencies.

Readme

brex

npm version CI license: MIT

An unofficial TypeScript SDK for the Brex API, maintained by Slingshot. Every client, method, and type is generated deterministically from Brex's published OpenAPI specs — the specs are vendored in this repo, generation is byte-for-byte reproducible, and CI fails if the committed code ever drifts from the specs.

  • Fully typed — request bodies, query params, and responses are typed straight from the specs
  • Tree-shakeable — import one API via subpaths (brex/payments) and the other nine never enter your bundle (~3.5 kB min for a single API)
  • Runs everywhere — native fetch, zero runtime dependencies, ESM-only; Node ≥ 20.19 (including require()), Bun, Deno, browsers, and edge runtimes
  • Auto-pagination — every list method is both a promise and an async iterator
  • Idempotency built inIdempotency-Key headers are sent automatically where Brex requires them

[!IMPORTANT] This is an unofficial library, not created, maintained, or in any way connected with Brex Inc. or any associated entity. "Brex" is a registered trademark of Brex, Inc. Use of the Brex API is subject to the Brex Access Agreement. Most usage involves highly sensitive financial data — you are entirely responsible for securing it.

Install

bun add brex
# or
npm install brex

Requires Node ≥ 20.19 (or any modern runtime with fetch). The package is ESM-only; on Node ≥ 20.19, require("brex") works too.

Quickstart

import { Brex } from "brex";

const brex = new Brex({ token: process.env.BREX_TOKEN! });

// Typed responses
const me = await brex.users.getMe();

// Create with an auto-generated Idempotency-Key
const vendor = await brex.vendors.create({ company_name: "Acme Inc" });

// One page…
const page = await brex.expenses.list({ limit: 100 });

// …or every item across all pages
for await (const expense of brex.expenses.list({ "expand[]": ["merchant"] })) {
  console.log(expense.id);
}

Generate a user token in your Brex dashboard, or obtain one via OAuth.

Tree-shakeable subpath imports

The root Brex class wires up all ten Brex APIs. If bundle size matters (browsers, edge functions), import only what you use — each subpath is an independent module graph:

import { createPaymentsClient } from "brex/payments";

const payments = createPaymentsClient({ token: process.env.BREX_TOKEN! });
const vendors = await payments.vendors.list({ name: "Acme" });

Every subpath also exports its resource classes (for composing with a shared BrexCore) and all of its schema types:

import type { VendorResponse, CreateVendorRequest } from "brex/payments";
import type { ExpandableExpense } from "brex/expenses";

Pagination

Every list endpoint returns a PagePromise — await it for a single page, iterate it for items, or step through pages:

// Single page (respects your `cursor`/`limit` params)
const page = await brex.transactions.listPrimaryCard({ limit: 50 });

// All items, across pages — follows next_cursor automatically
for await (const tx of brex.transactions.listPrimaryCard()) { /* … */ }

// Page-by-page
for await (const p of brex.transactions.listPrimaryCard().pages()) { /* … */ }

Authentication

Pass a static token, or a provider function (called per request — useful for OAuth token refresh):

const brex = new Brex({
  token: async () => getFreshAccessToken(),
});

Options

const brex = new Brex({
  token: "…",
  baseUrl: "staging",          // "production" (default), "staging", or any URL
  fetch: myCustomFetch,         // inject for proxies, retries, or tests
  defaultHeaders: { "x-app": "my-app" },
});

Per-request options are the last argument of every method:

await brex.vendors.create(
  { company_name: "Acme Inc" },
  {
    idempotencyKey: "order-1234",          // else an UUID is auto-generated where required
    signal: AbortSignal.timeout(10_000),   // abort/timeout
    headers: { "x-trace-id": "abc" },
  },
);

Retries are intentionally out of scope — wrap the injected fetch if you need them.

Error handling

Non-2xx responses throw a BrexError:

import { Brex, BrexError } from "brex";

try {
  await brex.vendors.get("vendor_id");
} catch (error) {
  if (error instanceof BrexError) {
    error.status;     // HTTP status code
    error.body;       // parsed JSON error body (or raw text)
    error.requestId;  // x-request-id header, if present
    error.headers;    // full response Headers
  }
}

API reference

Namespaces and methods are derived deterministically from the specs' tags and operationIds (with a small, reviewed overrides file). Methods requiring an Idempotency-Key send one automatically. ~~Struck-through~~ methods are deprecated upstream.

| Subpath import | Namespace | Methods | | --- | --- | --- | | brex/accounting | accountingIntegrations | create, disconnect, reactivate | | brex/accounting | accountingRecords | get, query, reportAccountingExportResults | | brex/budgets | budgetPrograms | get, list | | brex/budgets | budgetsV1 | archive, create, get, list, update | | brex/budgets | budgets | archive, create, get, list, update | | brex/budgets | spendLimits | archive, create, get, list, update | | brex/expenses | cardExpenses | ~~get~~, ~~list~~, update | | brex/expenses | expenses | get, list | | brex/expenses | receipts | match, upload | | brex/fields | fieldValues | create, delete, get, list, update | | brex/fields | fields | create, delete, get, list, update | | brex/onboarding | referrals | createDocument, createRequest, get, list, processDelayedEINDocument | | brex/payments | linkedAccounts | list | | brex/payments | transfers | create, createIncoming, get, list | | brex/payments | vendors | create, delete, get, list, update | | brex/team | cards | create, emailNumber, get, getNumber, list, lock, terminate, unlock, update | | brex/team | companies | get | | brex/team | departments | create, get, list | | brex/team | legalEntities | get, list | | brex/team | locations | create, get, list | | brex/team | titles | create, get, list | | brex/team | users | create, get, getLimit, getMe, list, setLimit, update | | brex/transactions | accounts | get, getPrimary, list, listCard, listCashStatements, listPrimaryCardStatements | | brex/transactions | transactions | listCash, listPrimaryCard | | brex/travel | trips | get, getBooking, list, listBookings | | brex/webhooks | webhookGroups | addMembers, create, delete, get, list, listMembers, removeMembers | | brex/webhooks | webhooks | create, delete, get, list, listSecrets, update |

Full request/response types for every method live in each subpath's exported schema types (e.g. import type { VendorResponse } from "brex/payments"), plus the raw paths/components OpenAPI shapes (PaymentsPaths, PaymentsComponents).

How generation works

specs/*.yaml  ──bun run generate──▶  src/<api>/{types,schemas,client}.gen.ts + entries
  • The 10 OpenAPI specs are vendored byte-for-byte in specs/ and re-fetched only by a human running bun run sync-specs.
  • bun run generate is a pure function of the specs, the overrides file, and exactly-pinned tool versions. Running it twice produces byte-identical output.
  • CI regenerates on every PR and fails on drift, so the published SDK can never silently diverge from the specs it claims to implement.
  • Types come from openapi-typescript; the thin client layer (~250 lines of hand-written runtime) is generated with method names cleaned from operationIds (createVendorvendors.create).

To pick up upstream API changes: bun run sync-specs && bun run generate, review the diff, commit both.

Migrating from v1

v2 is a ground-up rewrite; v1's hand-written wrapper is gone.

| v1 | v2 | | --- | --- | | new Brex(token) | new Brex({ token }) | | brex.request({ endpoint, method, … }) | Typed methods, e.g. brex.vendors.list() | | brex.vendors.list() (partial coverage) | Full coverage of all 10 published APIs | | isomorphic-unfetch polyfill | Native fetch, zero dependencies | | CommonJS + ESM | ESM-only (Node ≥ 20.19 require() still works) |

Contributing

See CONTRIBUTING.md. Releases are automated with Changesets and published to npm with provenance.

License

MIT