---
title: "Stablecoin API SDKs: how one OpenAPI spec keeps five languages in sync"
seoTitle: "Stablecoin API SDKs and OpenAPI docs"
description: "BlindPay's stablecoin API is described by one OpenAPI 3.1 spec that drives validation, docs, SDKs for Node, Python, Go, PHP, and Swift, and the MCP server."
date: "2026-09-11"
category: "payments"
author: "BlindPay Team"
faq:
  - q: "Which SDKs does the BlindPay stablecoin API support?"
    a: "Official SDKs for Node.js and TypeScript (@blindpay/node on npm), Python (blindpay on PyPI), Go (github.com/blindpaylabs/blindpay-go), PHP (Composer), and Swift (Swift Package Manager). For any other language, generate a typed client from the OpenAPI 3.1 spec at https://api.blindpay.com/doc."
  - q: "Where is the BlindPay OpenAPI spec?"
    a: "At https://api.blindpay.com/doc. It is an OpenAPI 3.1 document covering every public endpoint, and the interactive API reference lives at https://api.blindpay.com/reference."
  - q: "Can I generate my own client for a stablecoin API?"
    a: "Yes. Download the OpenAPI spec and run a generator for your language. For TypeScript, npx openapi-typescript https://api.blindpay.com/doc -o src/blindpay.d.ts produces types for every request and response."
  - q: "Are there endpoints the SDKs do not cover?"
    a: "A small number, currently POST /upload/extract for reading invoices with AI. Call those over raw HTTP even if you use an SDK for everything else."
  - q: "Can AI coding assistants use the BlindPay API?"
    a: "Yes. The BlindPay MCP server, run with npx -y @blindpay/mcp, lets Claude Code, Cursor, and Codex call the API against a development instance. Its tools are generated from the same contract as the OpenAPI spec, and the docs publish llms.txt plus markdown versions of every page."
---

BlindPay's stablecoin API is described by a single OpenAPI 3.1 specification at `https://api.blindpay.com/doc`. That one spec drives request validation on the server, the API reference, the official SDKs for Node, Python, Go, PHP, and Swift, and the tool surface of the MCP server. When a field changes, it changes everywhere at once, so the docs, the SDK, and the API can't disagree.

That's the design goal. Here's how it works, and why it matters more for a payments API than for most.

## Why does drift hurt more in a payments API?

Every API drifts. A field gets renamed, an enum gets a new value, an error changes shape, and the docs page updates a week later. Or never.

In most APIs that's annoying. In a payments API it's money. If your code doesn't know about a new payout status, a payout that went `on_hold` can look like it vanished. If the docs say an amount is in dollars and the API wants minor units, somebody sends 100 times what they meant. (Amounts in our API are integers in minor units. `500000` is 5,000.00. Every time.)

So the rule we work by: there is exactly one place a data shape is defined, and everything else is generated from it.

## Where does the spec come from?

Inside the API, every request and response shape is a Zod schema in one shared contract package. Those schemas do three jobs from one definition:

1. **Validate requests and responses** in the API itself.
2. **Generate the OpenAPI 3.1 document** published at `api.blindpay.com/doc`.
3. **Validate forms** in the BlindPay dashboard.

Nobody hand-writes the OpenAPI file. When an engineer changes a schema, the spec is regenerated from it. The spec on the server is always the spec in the code.

## What gets generated from that spec?

| Artifact | Where | What it gives you |
| --- | --- | --- |
| OpenAPI 3.1 spec | `https://api.blindpay.com/doc` | The full contract, machine-readable |
| API reference | `https://api.blindpay.com/reference` | Every endpoint, body, and response, interactive |
| Node.js / TypeScript SDK | `npm install @blindpay/node` | Typed methods and responses |
| Python SDK | `pip install blindpay` | The same surface in Python |
| Go SDK | `go get github.com/blindpaylabs/blindpay-go` | The same surface in Go |
| PHP SDK | Composer | The same surface in PHP |
| Swift SDK | Swift Package Manager | The same surface for iOS and macOS |
| MCP server | `npx -y @blindpay/mcp` | API tools for AI coding assistants |

Five SDKs, one contract. A new field shows up as a typed property, not a surprise inside a JSON blob.

## What does calling the API look like from an SDK?

The Node SDK takes your API key and instance id once, then every method returns the same `{ data, error }` shape:

```typescript
import { BlindPay } from '@blindpay/node'

const blindpay = new BlindPay({
  apiKey: process.env.BLINDPAY_API_KEY!,
  instanceId: process.env.BLINDPAY_INSTANCE_ID!,
})

const { data, error } = await blindpay.available.getRails()

if (error) {
  throw new Error(error.message)
}

console.log(data) // fully typed
```

No exceptions to catch for API errors, no guessing the error shape. You check `error`, you move on. The SDK readmes on [GitHub](https://github.com/blindpaylabs) have the full surface per language.

The same call over raw HTTP, if you'd rather skip the SDK:

```bash
curl https://api.blindpay.com/v1/instances/in_000000000000/customers \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

There's one base URL. Which environment you hit, development or production, is decided by which instance your key belongs to.

## What if my language isn't one of the five?

Generate a client. The spec is standard OpenAPI 3.1, so any generator works. For TypeScript types without the SDK:

```bash
npx openapi-typescript https://api.blindpay.com/doc -o src/blindpay.d.ts
```

Rust, Java, Kotlin, Ruby, C#: point your generator at the same URL. You'll get the same field names and enums the official SDKs use.

One caveat. A small number of endpoints are excluded from every generated SDK, currently `POST /upload/extract`, which reads invoices with AI. Call those over raw HTTP. The [SDK docs](/docs/sdks) keep that list current.

## How do error codes stay stable?

Errors are part of the contract too. Every error response carries a machine-readable code, like `idempotency_key_payload_mismatch` or `idempotency_key_in_flight`. Your code can branch on the code, not on a message string that might get reworded.

Idempotency is contract-level as well. Send an `Idempotency-Key` header on any write and a retry with the same body replays the original response with `Idempotency-Replayed: true`. A retry with a different body gets a `422`. That one header is what keeps a network timeout from turning into two payouts. Details in the [idempotency docs](/docs/learn/idempotency).

## How does this help AI coding assistants?

The same contract generates the tools in the [BlindPay MCP server](/blog/mcp). When an endpoint is added or removed, the MCP tool surface changes with it, so an agent never calls a tool the API no longer has.

Around it:

- **llms.txt and markdown pages.** The docs publish an llms.txt index and a markdown version of every page, so an agent reads the same reference you do.
- **[Agent Skills](/blog/agent-skills).** Install with `npx skills add blindpaylabs/skills` to give Claude Code, Cursor, or Codex working knowledge of payouts, payins, and customers.
- **[The CLI](/blog/cli).** JSON output and predictable exit codes, so scripts and agents can drive it.

The practical effect: an assistant can build and test a payout flow against a development instance with the right field names on the first try, because it's reading the same contract the API enforces.

## What does this mean for an integration timeline?

Faster, and fewer surprises in production. A first payout on a development instance is usually a day of work, and most of that day is your own ledger and UI, not the API. Development instances are free, skip banking-partner review, and accept sentinel amounts (`66600` forces `failed`, `77700` forces `refunded`) so you can test every path. Payout timing by rail is in [how long a stablecoin payout takes](/resources/more/stablecoin-payout-settlement-times). The full flow, endpoint by endpoint, is in our [developer guide to integrating a stablecoin API](/resources/more/how-to-integrate-a-stablecoin-api).

## Where does BlindPay fit?

[BlindPay](/global-payments) is a stablecoin API for cross-border payouts and collections: USDC or USDT in, local currency out over Pix, SPEI, ACH, RTP, SEPA, and SWIFT (POBO/COBO) to 100+ countries, with no pre-funding. KYC, KYB, and sanctions screening run inside the API. [Virtual USD accounts](/virtual-accounts) turn ACH, wire, and SWIFT deposits into stablecoins. And every piece of it is described by the one spec above.

## What to do next

Install the SDK for your stack, or run `npx openapi-typescript https://api.blindpay.com/doc` and read the generated types for ten minutes. You'll understand the whole API surface faster than any docs page could explain it. Then create a development instance and send your first test payout with the [payout quickstart](/docs/quickstart-payout).

*This article is for general information only and is not legal, tax, or financial advice.*
