Skip to content
← BlogDeveloper

The Norbelys OpenAPI spec: 83 operations, one document

A practical tour of api.norbelys.com/openapi.json: what's in it, how to import it into Postman or Insomnia, and why one spec drives every SDK and the CLI.

By Gabriel Lara, Developer Relations, Norbelys

Founder-reviewed ·How we research and correct articles

Every operation Norbelys’s REST API exposes is described, machine-readably, at one URL: https://api.norbelys.com/openapi.json. It’s OpenAPI 3.1, it currently describes 83 operations, and it isn’t a static file someone hand maintains next to the code — it’s generated straight from the same typed contract the API worker implements, so it can’t drift from what the API actually does. This is a tour of what’s in it and what you can point at it.

What’s actually in the document

The spec follows the five canonical patterns the whole API is built from, so its shape is predictable before you’ve read a single operation: resource CRUD (/v1/people, /v1/senders, /v1/domains, /v1/programs, /v1/suppressions…), relationship sub-collections, ?view= projections, :verb actions, and the /v1/jobs bulk pattern. Every request and response schema carries a .describe() annotation with a realistic example, so the generated spec is self-documenting — a field like givenName shows up with an actual example value, not just a type, which is what makes Postman, Insomnia, and code generators produce usable stubs instead of placeholder strings.

curl https://api.norbelys.com/openapi.json | jq '.info, (.paths | keys | length)'

That single request tells you the API version and how many paths exist right now — useful as a sanity check before you generate anything against it, since the number changes as the surface grows.

Authentication is in the spec, not just the docs

An OpenAPI document isn’t only endpoint shapes — it also declares how a client is supposed to authenticate, under securitySchemes, which is what lets an imported Postman collection or a generated SDK pre-wire the right header instead of you guessing. Norbelys supports two authentication paths, both discoverable from the spec and from the developer portal: a static, org-scoped API key (ak_…) sent as Authorization: Bearer ak_… for headless and CI callers, and OAuth 2.1 for interactive agents that register dynamically via the metadata at /.well-known/oauth-protected-resource. Every operation in the document references one of these schemes, so a client generator knows, per endpoint, exactly what credential to attach — it isn’t left to a paragraph of prose elsewhere that a code generator can’t read.

Why OpenAPI 3.1, and why that version matters

Norbelys publishes 3.1 specifically, not the more common 3.0. The practical difference is that 3.1 aligns its schema format with modern JSON Schema instead of the constrained subset 3.0 used, which matters most for how precisely nullable fields, oneOf unions, and nested object validation get described. Since Norbelys’s contract schemas carry real validation logic — required fields, enum constraints, format rules on things like email and Idempotency-Key — 3.1 is the version that can express that logic exactly, rather than approximating it and leaving a generated client to under- or over-validate.

Importing it into an API client

Postman, Insomnia, and most REST clients can import an OpenAPI URL directly and turn it into a full, organized request collection — no manual endpoint entry.

  1. Open the import dialog

    In Postman: File → Import. In Insomnia: Application → Preferences → Data → Import Data, or the Import button on a workspace.

  2. Point it at the spec URL

    Paste https://api.norbelys.com/openapi.json as a URL import rather than uploading a file — that way re-importing later always pulls the current spec.

  3. Set the bearer token

    Add an Authorization header (or the client's Bearer Token auth type) with your org-scoped API key: Authorization: Bearer ak_live_.... Keys are created in the app and scoped to one organization.

  4. Confirm the base URL

    The imported collection should resolve to https://api.norbelys.com/v1 for every request — check the collection or environment variable if your client separates server URL from paths.

From there every operation in the spec — every resource, action, view, and job — is a ready-to-run request with the right method, path, and example body already filled in.

Generating your own client

Because the spec is standard OpenAPI 3.1, it works with any generic OpenAPI code generator, not just the four SDKs Norbelys ships. openapi-typescript, openapi-generator-cli, or your language’s equivalent will all happily consume it directly:

generate a typed TS client
$ npx openapi-typescript https://api.norbelys.com/openapi.json -o norbelys-schema.d.ts✔ Generating types...✔ norbelys-schema.d.ts (83 operations)

That’s a legitimate path if you want a client in a language Norbelys doesn’t officially publish an SDK for, or you want generation baked into your own build pipeline instead of depending on an npm/PyPI release cadence. The official SDKs exist for convenience — @norbelys/sdk on npm, norbelys on PyPI, plus Go and Ruby — but they’re generated from this exact document, so a client you generate yourself against the same spec is functionally equivalent, just without the hand-picked ergonomics (retry helpers, pagination iterators) the official packages add on top.

Why “one spec” is the actual point

The interesting property of the OpenAPI document isn’t that it exists — plenty of APIs publish a spec that’s really a static export nobody keeps current. It’s that this one is the only description of the API surface anywhere, and everything downstream is generated from it: the four SDKs, the norbelys CLI, and the MCP server at mcp.norbelys.com/mcp, whose tool list is built by walking the same operations this document describes (the MCP side of that story — auth, tool count, the security model — is covered in running cold email from your AI agent, so it’s not repeated here).

That single-source property is also why the field names you see in the spec are the same ones you get back in every response, in every SDK, in every MCP tool call — there’s no serializer translating between “the API’s names” and “the SDK’s names,” because there’s only one name per field, chosen from Schema.org vocabulary where one exists. A rename in the contract shows up in the spec, the regenerated SDKs, and the CLI’s help output in the same release. Nothing gets hand-edited into sync after the fact, because there’s nothing to keep in sync — there’s one document, and everything else is a projection of it.

Reading it like a developer, not a machine

You don’t have to run a generator to get value from the spec. Fetching it and grepping the paths object is often the fastest way to answer “does this resource support that operation” without leaving your terminal — faster than searching prose documentation, and guaranteed current because it’s the same document the API worker validates requests against.

curl -s https://api.norbelys.com/openapi.json | jq '.paths | keys' | grep senders

Whichever client or language you end up calling it from, this document is the answer either way: it’s the one artifact that describes what you can actually call, regardless of which client or language you’re calling it from. Start here, then work outward to the five patterns that explain why every operation looks the way it does.

Frequently asked questions

Does the OpenAPI spec ever fall out of sync with the live API?

No. The spec is generated from the same contract package the API worker uses to implement every route, so there's no separate document to forget to update. If an endpoint changes, the same change that ships it regenerates the spec.

Do I need an API key to fetch the spec itself?

No. The OpenAPI document at api.norbelys.com/openapi.json is public and describes the surface, including its own auth requirements. You only need a key to actually call the described endpoints.

Which languages have an official generated SDK?

TypeScript (@norbelys/sdk on npm), Python (norbelys on PyPI), Go, and Ruby. All four are generated from the same OpenAPI document, so they stay behaviorally identical to each other and to the spec.

Can I generate a client in a language without an official SDK?

Yes. Because the document is standard OpenAPI 3.1, any generic OpenAPI code generator — openapi-typescript, openapi-generator-cli, and similar tools across other languages — can consume it directly and produce a working client.