The @norbelys/sdk quickstart: from npm install to your first API call
Install the official Node/TypeScript SDK, authenticate with an API key, and make your first typed call against the Norbelys API — a complete quickstart.
By Gabriel Lara, Developer Relations, Norbelys
Founder-reviewed ·How we research and correct articles
If you’re building on Node or TypeScript and you’d rather not hand-write fetch
calls against the Norbelys REST API, @norbelys/sdk is the
official client. It’s generated straight from our OpenAPI spec — every
resource, every field, every parameter is typed — so your editor tells you
what’s available instead of a browser tab full of docs.
This is a start-to-finish quickstart: install the package, get an API key, make your first authenticated call, and know where to go next.
What you’re installing
@norbelys/sdk wraps the same REST API that powers the
Norbelys dashboard — there’s no separate “SDK-only” surface. Under the hood
it’s a typed HTTP client: it builds requests, attaches your Authorization
header, parses the JSON response, and gives you back typed objects instead of
any. If you already know the API shape from
the OpenAPI spec, the SDK will feel
immediately familiar — it’s the same resources, the same fields, just with
autocomplete.
Before you start: get an API key
Every call to the Norbelys API needs an org-scoped API key. Create one
from the dashboard, then keep it out of source control — treat it like any
other production secret. If you’re building something that runs on a
schedule or in CI rather than interactively, an API key is exactly the right
credential (interactive AI agents have a separate OAuth 2.1 path, described
in auth.md, which doesn’t apply here).
From zero to a first call
Install the package
Add @norbelys/sdk to your project with npm, pnpm, or bun. It ships its own TypeScript types, so there's no separate @types package to install.
Set your API key
Store it as an environment variable (NORBELYS_API_KEY is the conventional name) rather than a literal string in your code. The SDK reads it when you construct the client.
Construct the client
Create a client instance once, near your app's entry point, and reuse it — the same pattern you'd use for any HTTP client SDK (a Stripe or Twilio client, for example).
Make your first call
List a resource you already have data for — people or senders are good first calls — and log the result to confirm the round trip works end to end.
Move to a real operation
Once a read call succeeds, try a write: create a sender, or send a single message through the one send door. Typed inputs mean mistakes surface at compile time, not in production.
Install and run
A minimal script looks like this. Construct the client with your key, then
call a resource method — the shape mirrors the REST endpoint one-to-one
(GET /v1/people becomes something like client.people.list()):
import { Norbelys } from "@norbelys/sdk";
const client = new Norbelys({ apiKey: process.env.NORBELYS_API_KEY });
const { data } = await client.people.list({ limit: 5 });
for (const person of data) {
console.log(person.email, person.givenName);
}
Because the client is generated from the OpenAPI spec, person here isn’t
any — your editor knows it has email, givenName, familyName, and the
rest of the Schema.org-mapped fields
the API returns, and it’ll flag a typo in a field name before you ever run
the code.
A first write: creating a sender
Reads are a good sanity check, but the SDK earns its keep on writes, where typed inputs catch mistakes immediately. Creating a sender is a common first write call — every send in Norbelys goes out through one:
const sender = await client.senders.create({
email: "outreach@yourdomain.com",
name: "Outreach",
});
console.log(sender.id); // snd_...
If you leave off a required field, or pass a string where the type expects a
number, that’s a compile error in your editor — not a 422 you discover
after deploying. That’s the whole value proposition of a generated client
over raw fetch: the contract is enforced before the request ever leaves
your machine.
Handling errors
Every API error comes back in one shape —
{ error: { code, message, field? } } — and the SDK surfaces that as a
typed exception you can catch and branch on, rather than a bag of
possibly-undefined fields:
try {
await client.senders.create({ email: "not-an-email" });
} catch (err) {
if (err instanceof Norbelys.APIError) {
console.error(err.code, err.message, err.field);
}
}
Pagination
List endpoints use cursor pagination — never offset — because IDs are
prefixed cuid2 and aren’t time-sortable, so a stable cursor over
(createdAt, id) is the only correct way to page through a growing list.
Expect the SDK to expose a cursor you pass back in on the next call, mirroring
the raw ?cursor=&limit= query parameters described in
the OpenAPI spec walkthrough.
Configuring the client beyond the API key
The constructor accepts more than just apiKey in practice — expect options
for things like a request timeout, a custom baseUrl (useful if you’re
routing through an internal proxy), and a maxRetries count for transient
network failures. None of these are required for a first call, but they’re
worth setting explicitly once code moves past a prototype:
const client = new Norbelys({
apiKey: process.env.NORBELYS_API_KEY,
timeout: 10_000,
maxRetries: 2,
});
A sensible retry count matters more than it might seem for anything that
calls the send door — a transient network blip retried automatically is a
non-event; the same blip left unhandled in application code is a support
ticket. Just make sure retries are only applied to idempotent calls, or pair
them with the Idempotency-Key header the API already supports on
state-changing POST requests, so a retried create can’t double-send.
Using the client inside a Worker
Because Norbelys’s own control plane runs on Cloudflare Workers,
the Node SDK is built to work the same way inside yours — no Node-only APIs
it secretly depends on. Construct the client once per request (or once per
isolate, if you’re caching it on globalThis), read the API key from your
Worker’s secret bindings instead of process.env, and the rest of the code
looks identical to any other Node environment:
export default {
async fetch(request: Request, env: Env) {
const client = new Norbelys({ apiKey: env.NORBELYS_API_KEY });
const { data } = await client.people.list({ limit: 10 });
return Response.json(data);
},
};
This is also the shape you’d reach for if you’re building an integration that reacts to Norbelys data on a schedule rather than waiting on a push — see what to use instead of webhooks if that’s the integration you have in mind.
TypeScript strictness pays off here specifically
If your project runs with strict: true, the generated types will flag
things a loosely-typed HTTP client never would: a field that’s optional on
create but required on update, a union type on status that doesn’t
include a value you assumed existed, an enum that changed shape between API
versions. None of that is the SDK being fussy — it’s the same validation
the API would perform server-side, surfaced at compile time instead of as a
runtime 422.
Where this fits with everything else
The SDK, the CLI, and the MCP server are three different front doors onto the exact same contract — none of them can drift from the real API because all four are generated from one OpenAPI spec. If you’d rather work from a terminal than write Node, the CLI covers the same ground; if you’re wiring up an AI agent instead of a script, MCP is the better fit. Pick based on where the calling code lives, not because one is “more official” than another.
If you’re not sure Node is even the right language for your integration — maybe this is a data pipeline, or a Rails app, or a Cloudflare Worker — the SDK comparison guide walks through when Python, Go, or Ruby is the better call.
Next steps
- Read the OpenAPI spec explainer to understand the full resource model behind every SDK call.
- If Python fits your stack better, the
Python quickstart covers the same
ground with
pip install norbelys. - For webhook-shaped use cases, note that outbound event webhooks aren’t live yet — see what to build instead today.
- Browse the full surface at the developer portal, or explore what Norbe, the AI operator, automates on top of this same API.