---
title: "Node.js SDK Quickstart"
canonical: "https://test.abhinandan.one/node-sdk-quickstart"
markdown_url: "https://test.abhinandan.one/node-sdk-quickstart.md"
publisher: "Primitive SDKs"
kind: "quickstart"
content_type: "reference"
category: "Node.js SDK"
description: "Install @primitivedotdev/sdk, set PRIMITIVE_API_KEY, and receive and reply to an inbound email from a Next.js route handler in under 5 minutes."
keywords: ["@primitivedotdev/sdk", "primitive.receive", "primitive.client", "PRIMITIVE_API_KEY", "PRIMITIVE_WEBHOOK_SECRET", "client.reply"]
last_modified: "2026-08-21T18:22:43.359885+00:00"
published_at: "2026-08-11T18:55:01.578772+00:00"
source_files:
  - "sdk-node/README.md"
sections:
  - {anchor: "step-install-the-sdk", title: "Install the SDK"}
  - {anchor: "step-set-your-api-key-and-webhook-secret", title: "Set your API key and webhook secret"}
  - {anchor: "step-receive-and-reply-in-a-nextjs-route", title: "Receive and reply in a Next.js route"}
  - {anchor: "step-point-an-inbound-address-at-the-route-and-verify", title: "Point an inbound address at the route and verify"}
  - {anchor: "send-a-new-email-instead-of-replying", title: "Send a new email instead of replying"}
  - {anchor: "next-steps", title: "Next steps"}
---

> Documentation index: https://test.abhinandan.one/llms.txt

# Node.js SDK Quickstart

Install @primitivedotdev/sdk, set your API key, and wire up a Next.js route that receives an inbound email and replies to it in under 5 minutes.

Get a Next.js route receiving and replying to real email in one pass: install `@primitivedotdev/sdk`, set your API key, and handle your first inbound webhook.

> **Note:** Requires Node.js 22 or newer. You need a Primitive account and dashboard access to get an API key and a webhook secret.

> **Tip:** Building in Python or Go instead? See the [Python SDK Quickstart](https://test.abhinandan.one/python-sdk-quickstart.md) or the [Go SDK Quickstart](https://test.abhinandan.one/go-sdk-quickstart.md). All three SDKs implement the identical inbound/outbound model, so pick by language, not by capability gap.

> **Tip:** Just need the CLI for your terminal or CI, not application code? Run `npm install -g primitive` instead; `@primitivedotdev/sdk` no longer ships a `primitive` bin. See [What is the Primitive CLI?](https://test.abhinandan.one/cli-overview.md)

### 1. Install the SDK

```bash
npm install @primitivedotdev/sdk
```

### 2. Set your API key and webhook secret

Get an API key from your [dashboard](https://primitive.dev) and export it. The examples below read it from `process.env.PRIMITIVE_API_KEY`.

```bash
export PRIMITIVE_API_KEY=prim_test
export PRIMITIVE_WEBHOOK_SECRET=whsec_...
```

`PRIMITIVE_API_KEY` authenticates outbound calls (`client.send`, `client.reply`, `client.forward`). `PRIMITIVE_WEBHOOK_SECRET` verifies that inbound webhook deliveries actually came from Primitive: `primitive.receive(...)` checks the `Primitive-Signature: t=<unix-seconds>,v1=<hex>` header against it automatically and rejects deliveries whose timestamp is more than 300 seconds old. See [Webhook Events Overview](https://test.abhinandan.one/webhook-events.md) for the full signature contract.

### 3. Receive and reply in a Next.js route

Create a route handler that receives an inbound email and replies to it:

```ts
// app/api/inbound/route.ts
import primitive from "@primitivedotdev/sdk";

export const runtime = "nodejs";
export const maxDuration = 300;

const client = primitive.client({
  apiKey: process.env.PRIMITIVE_API_KEY!,
});

export async function POST(req: Request) {
  const email = await primitive.receive(req, {
    secret: process.env.PRIMITIVE_WEBHOOK_SECRET!,
  });

  await client.reply(email, "Thank you for your email.");

  return Response.json({ ok: true });
}
```

`primitive.receive(...)` reads the request body, verifies the HMAC-SHA256 signature against your webhook secret (rejecting expired or tampered deliveries), and returns a `ReceivedEmail`, the SDK-normalized representation of the inbound email. `client.reply(email, ...)` derives threading and the `Re:` subject from the parent message server-side, so no manual header wiring is required. See the [inbound and outbound email model](https://test.abhinandan.one/email-model.md) for the full object.

### 4. Point an inbound address at the route and verify

Configure a Primitive inbox or domain to deliver to this route's URL (see your dashboard for endpoint setup), then send a test email to that address.

Expected result: the sender receives an automatic reply of "Thank you for your email.", and your route returns:

```json
{ "ok": true }
```

If the route instead throws a `WebhookVerificationError`, check that `PRIMITIVE_WEBHOOK_SECRET` matches the secret shown in your dashboard and that you pass the raw `Request` object into `primitive.receive`. Verification runs over the exact request bytes, so a body that has already been parsed and re-serialized will not match.

## Send a new email instead of replying

Not handling inbound mail yet? Send outbound mail directly with `client.send`:

```ts
import primitive from "@primitivedotdev/sdk";

const client = primitive.client({
  apiKey: process.env.PRIMITIVE_API_KEY!,
});

const result = await client.send({
  from: "Support <support@example.com>",
  to: "alice@example.com",
  subject: "Hello",
  bodyText: "Hi there",
});

console.log(result.id, result.status, result.queueId);
```

By default, `send` returns as soon as Primitive accepts the message for delivery. Pass `wait: true` (with `waitTimeoutMs`, default 30000) only when you need the first downstream SMTP outcome before responding. Full send/reply/forward behavior, attachments, and wait mode are covered in [Sending, Replying, and Forwarding Email](https://test.abhinandan.one/node-sdk-sending-email.md).
