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

What is the Primitive Node.js SDK?

@primitivedotdev/sdk is the official Node.js client for Primitive's inbound/outbound email platform, exposing a small default surface for send/receive/reply plus dedicated subpaths for webhooks, x402 payments, the generated API client, and raw MIME parsing.

@primitivedotdev/sdk is the official Node.js library for Primitive, an email API for sending and receiving programmatic mail. It gives you a typed client for receiving and verifying inbound webhooks, sending mail, parsing raw MIME, calling the full HTTP API, and moving USDC with x402 payments.

Requires Node.js 22 or newer. Install it with:

npm install @primitivedotdev/sdk
Note

Looking for the terminal instead of application code? The CLI ships as a separate package. Run npm install -g primitive (or npx primitive@latest <command>); @primitivedotdev/sdk no longer ships a primitive bin. See What is the Primitive CLI?

The default import is deliberately small#

The root import (import primitive from "@primitivedotdev/sdk") covers the two things almost every integration needs on day one: receiving inbound webhook deliveries and sending mail.

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 });
}

This is the shared receive-then-send/reply/forward model every SDK implements; see Inbound and Outbound Email Model for the field-by-field reference.

Everything past that default is reachable through a small set of subpath imports, each scoped to one job.

Subpath export map#

SubpathWhat it's forOwning page
@primitivedotdev/sdk (root)primitive.receive, primitive.client, client.send/reply/forwardSending, Replying, and Forwarding Email, Receiving Inbound Email
@primitivedotdev/sdk/webhookverifyWebhookSignature, handleWebhookEvent, event type guards, download-token helpersWebhook Signature Verification, Handling Payment and Interaction Webhook Events
@primitivedotdev/sdk/apiPrimitiveApiClient, createPrimitiveClient, client.memories, isTrustedSender, validateEmailAuth, normalizeReceivedEmail, the Workers-safe surfaceGenerated API Client and Primitive Memories, Verifying Inbound Email Authenticity
@primitivedotdev/sdk/x402createX402Client, parseEmailChallengeFromPart, the low-level signing primitivesx402 Payments Overview, Paying a Challenge
@primitivedotdev/sdk/openapiThe generated OpenAPI document export, for JavaScript consumers that need the raw specOpenAPI Spec Normalization and Codegen Artifacts
@primitivedotdev/sdk/contractbuildEmailReceivedEvent, producer-side types for constructing schema-valid webhook fixturesBuilding Webhook Payloads (Contract Module)
@primitivedotdev/sdk/parserparseFromHeader, parseFromHeaderLoose, raw MIME address parsingRaw MIME Address Parsing (parser/address)

Two subpaths matter architecturally, not just organizationally:

  • /api is Workers-safe. It re-exports isTrustedSender, validateEmailAuth, and normalizeReceivedEmail specifically so Primitive Functions handlers, which run on an edge runtime, can make trust decisions and normalize inbound events without pulling in node:crypto. The root import and /webhook both pull node:crypto through the Node-crypto signing helpers and break a Workers-style bundle.
  • /api also carries the generated HTTP surface. PrimitiveApiClient and the raw generated operations (setMemory, getMemory, searchMemories, deleteMemory, getAccount, and every other OpenAPI operation) live here, re-exported from the workspace-internal @primitivedotdev/api-core package. See What is API Core? for how that package is built and bundled.

Why the surface is split this way#

The split mirrors how integrations actually grow. Most handlers start and stay on the root import: receive an email, reply to it, done. Some need signature verification without a standard Request object, where the framework hands you raw bytes and headers instead; that's /webhook. Some need Primitive Memories or an uncommon operation the high-level client doesn't wrap; that's /api. Only integrations doing agent-to-agent payments touch /x402, and only tooling that builds or tests webhook fixtures touches /contract.

Each subpath is a separate entry point, so a Next.js route that only replies to email never bundles the x402 signing code.

A concrete example: three subpaths in one handler#

A Primitive Function that replies to trusted senders, stores state in Primitive Memories, and settles an x402 payment touches three subpaths at once:

import { createPrimitiveClient, isTrustedSender } from "@primitivedotdev/sdk/api";
import { createX402Client } from "@primitivedotdev/sdk/x402";

const client = createPrimitiveClient({ apiKey: process.env.PRIMITIVE_API_KEY! });
const x402 = createX402Client({ apiKey: process.env.PRIMITIVE_API_KEY! });

export default {
  async fetch(request: Request): Promise<Response> {
    const event = await request.json();

    const trust = isTrustedSender(event, { domain: "example.com" });
    if (!trust.trusted) {
      return new Response("untrusted sender", { status: 403 });
    }

    await client.memories.set({ key: "last_seen", value: { at: Date.now() } });

    const challenge = await x402.charge({ amountUsdc: "0.01", network: "base-sepolia" });
    return Response.json({ challenge });
  },
};

Every import here comes from /api or /x402 rather than the root. That is exactly the Workers-safe path a Primitive Function needs.

What lives outside these subpaths#

Two capabilities ship as part of the SDK but aren't separate subpaths:

  • Primitive Payloads (streaming large, end-to-end-encrypted attachments with pushFile/pushBytes/pullFile) backs client.sendAttachment, which picks inline delivery versus a payload reference by size for you. Inline attachments are the default under the inline size cap (~25-30 MiB). See Primitive Payloads: Streaming Large Attachments.
  • Agent accounts (client.agent.createAccount, the email-claim flow) hang off the same client object you get from primitive.client(...). See Agent Accounts.

Next steps#

Was this page helpful?

© Primitive SDKs

Powered by Browzer