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
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#
| Subpath | What it's for | Owning page |
|---|---|---|
@primitivedotdev/sdk (root) | primitive.receive, primitive.client, client.send/reply/forward | Sending, Replying, and Forwarding Email, Receiving Inbound Email |
@primitivedotdev/sdk/webhook | verifyWebhookSignature, handleWebhookEvent, event type guards, download-token helpers | Webhook Signature Verification, Handling Payment and Interaction Webhook Events |
@primitivedotdev/sdk/api | PrimitiveApiClient, createPrimitiveClient, client.memories, isTrustedSender, validateEmailAuth, normalizeReceivedEmail, the Workers-safe surface | Generated API Client and Primitive Memories, Verifying Inbound Email Authenticity |
@primitivedotdev/sdk/x402 | createX402Client, parseEmailChallengeFromPart, the low-level signing primitives | x402 Payments Overview, Paying a Challenge |
@primitivedotdev/sdk/openapi | The generated OpenAPI document export, for JavaScript consumers that need the raw spec | OpenAPI Spec Normalization and Codegen Artifacts |
@primitivedotdev/sdk/contract | buildEmailReceivedEvent, producer-side types for constructing schema-valid webhook fixtures | Building Webhook Payloads (Contract Module) |
@primitivedotdev/sdk/parser | parseFromHeader, parseFromHeaderLoose, raw MIME address parsing | Raw MIME Address Parsing (parser/address) |
Two subpaths matter architecturally, not just organizationally:
/apiis Workers-safe. It re-exportsisTrustedSender,validateEmailAuth, andnormalizeReceivedEmailspecifically so Primitive Functions handlers, which run on an edge runtime, can make trust decisions and normalize inbound events without pulling innode:crypto. The root import and/webhookboth pullnode:cryptothrough the Node-crypto signing helpers and break a Workers-style bundle./apialso carries the generated HTTP surface.PrimitiveApiClientand the raw generated operations (setMemory,getMemory,searchMemories,deleteMemory,getAccount, and every other OpenAPI operation) live here, re-exported from the workspace-internal@primitivedotdev/api-corepackage. 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) backsclient.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 sameclientobject you get fromprimitive.client(...). See Agent Accounts.
Next steps#
Install the SDK, set your API key, and receive and reply to your first inbound email in a Next.js route.
Sending, Replying, and Forwarding EmailUse client.send, client.reply, and client.forward with wait mode and attachments.
Generated API Client and Primitive MemoriesCall any Primitive HTTP endpoint directly and store durable JSON records.
x402 Payments OverviewUnderstand the non-custodial USDC payment model shared by every SDK.
Was this page helpful?