Documentation Index: Fetch llms.txt first to discover every published page. This page is also available as Markdown at /node-sdk-quickstart.md.
Verified · 8/11/2026

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 or the Go SDK Quickstart. 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?

  1. 1

    Install the SDK#

    npm install @primitivedotdev/sdk
    
  2. 2

    Set your API key and webhook secret#

    Get an API key from your dashboard and export it. The examples below read it from process.env.PRIMITIVE_API_KEY.

    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 for the full signature contract.

  3. 3

    Receive and reply in a Next.js route#

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

    // 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 for the full object.

  4. 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:

    { "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:

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.

Next steps#

Was this page helpful?

© Primitive SDKs

Powered by Browzer