The Sendrealm JavaScript SDK is a typed client for the Sendrealm public API. Use it from trusted server-side or edge environments to send emails, send push notifications, ingest events, manage contacts, work with audiences, publish templates, control automations, and manage topics.
This SDK is for API access with a Sendrealm API key. It is different from the mobile SDKs. Mobile SDKs run inside end-user apps and register push tokens. The JavaScript SDK usually runs in your backend, worker, queue consumer, or serverless function.
Do not expose a Sendrealm API key in browser JavaScript or mobile app code. API keys are server-side secrets.
When To Use This SDK
Use the JavaScript SDK when your application needs to call Sendrealm from code you control, such as:
- Sending transactional email from a backend.
- Sending push notifications from a server event.
- Ingesting customer events such as
order.completed.
- Creating or updating contacts after sign-up.
- Adding contacts to audiences.
- Managing topics and subscriptions.
- Publishing templates or starting automations from internal tooling.
Do not use this SDK to register mobile devices for push. Use the Android, iOS, or React Native SDK for device registration.
Runtime Support
The SDK uses native fetch and has no runtime dependencies.
- Node.js 18 or newer
- Cloudflare Workers
- Deno
- Bun
- Vercel Edge Runtime
- Other runtimes with
fetch, Headers, Request, and Response
Browser-like runtimes are blocked by default to reduce the risk of exposing secret API keys. Use dangerouslyAllowBrowser: true only if you fully understand that the API key can be exposed to users.
Install
npm install @sendrealm/sdk
Create An API Key
Create an API key in the Sendrealm dashboard before creating the client. Store it in your secret manager or environment variables.
See API Keys for dashboard setup.
Create A Client
The simplest setup reads the API key from your environment:
import Sendrealm from "@sendrealm/sdk";
const client = new Sendrealm({
apiKey: process.env.SENDREALM_API_KEY,
});
The client also reads these environment variables automatically when available:
SENDREALM_API_KEY
SENDREALM_BASE_URL
That means this also works:
import Sendrealm from "@sendrealm/sdk";
const client = new Sendrealm();
Client Options
Use client options when you need custom timeouts, retries, headers, or a custom fetch implementation:
const client = new Sendrealm({
apiKey: "sk_...",
timeout: 60_000,
maxRetries: 0,
fetch: customFetch,
defaultHeaders: {
"X-App": "my-service",
},
});
Important options:
apiKey: required unless SENDREALM_API_KEY is set.
timeout: request timeout in milliseconds.
maxRetries: number of automatic retries for retryable failures.
fetch: custom fetch implementation.
defaultHeaders: headers sent with every request.
defaultQuery: query parameters sent with every request.
dangerouslyAllowBrowser: allows browser-like runtimes. Avoid this for secret API keys.
apiKey may also be an async function. This is useful when your service rotates credentials:
const client = new Sendrealm({
apiKey: async () => await getRotatedApiKey(),
});
Send Email
Use client.emails.send to send transactional or application email:
const email = await client.emails.send({
from: "hello@example.com",
to: ["user@example.com"],
subject: "Welcome",
html: "<p>Hello from Sendrealm</p>",
});
Before sending production email, make sure the sending domain is verified in Sendrealm. A verified domain improves deliverability and prevents other teams from sending as a domain they do not control.
Common fields:
from: sender address.
to: recipient addresses.
cc and bcc: optional copied recipients.
reply_to: optional reply-to addresses.
subject: subject line.
text and html: message body.
attachments: base64 encoded file attachments.
headers: custom message headers.
tags: message tags for reporting or filtering.
Send Push
Use client.push.notifications.send to send a push notification to registered mobile devices:
await client.push.notifications.send({
app_id: "app_123",
emails: ["user@example.com"],
notification: {
title: "Your order shipped",
body: "Track it now",
launch_url: "https://example.com/orders/123",
},
});
Push sending requires mobile setup first:
- Android devices must initialize the Android or React Native SDK and register FCM tokens.
- iOS devices must initialize the iOS or React Native SDK and register APNs tokens.
- Firebase and APNs credentials must be uploaded in Sendrealm.
You can target push recipients by tokens, device IDs, contact IDs, external IDs, emails, or audiences. Choose the most stable identifier your backend has available. For user-level notifications, external_ids, contact_ids, or emails are usually easier to reason about than raw push tokens.
Push Delivery Expectations
A successful API response means Sendrealm accepted the send request and started provider delivery. It does not mean every target device displayed the notification instantly.
Final delivery depends on Firebase Cloud Messaging, APNs, the target device, the operating system, network connectivity, user notification settings, app state, power management, and priority. Android can delay normal-priority messages during Doze. iOS can throttle background update notifications. Both platforms can suppress display when the user disables notifications or when device-specific policies apply.
For backend logic, design around these realities:
- Use push as a best-effort notification channel, not as the only source of truth.
- Store important state on your backend so the app can fetch it after opening.
- Use high priority only for urgent, user-visible Android notifications.
- Avoid sending large bursts to the same device.
- Expect stale or inactive device tokens over time.
- Track app-side open and click events instead of assuming every send was seen.
Ingest Events
Events are how your backend tells Sendrealm that something happened:
await client.events.ingest({
event: "order.completed",
email: "user@example.com",
payload: {
order_id: "order_123",
total: 42,
},
idempotency_key: "order_123_completed",
});
Each event must include one identity:
contact_id
external_id
email
Use an idempotency_key when your system might retry the same event. This lets Sendrealm treat repeated submissions as the same logical event instead of creating duplicates.
Good event names are lowercase and stable:
order.completed
billing.payment_failed
user.onboarded
checkout.started
Avoid putting sensitive personal data in event payloads unless your team intentionally wants that data in Sendrealm.
Contacts represent people in Sendrealm. You can list contacts with cursor pagination:
for await (const contact of client.contacts.list({ limit: 100 })) {
console.log(contact.email);
}
Create a contact:
const contact = await client.contacts.create({
email: "user@example.com",
fields: {
first_name: "Olivia",
plan: "pro",
},
});
Update a contact:
await client.contacts.update(contact.id, {
fields: {
plan: "enterprise",
},
});
Use your backend for authoritative customer fields such as billing plan, account status, compliance flags, and verified profile data.
Some list endpoints return cursor pages. You can consume every item with for await:
for await (const contact of client.contacts.list({ limit: 100 })) {
console.log(contact.email);
}
Or inspect pages manually:
let page = await client.contacts.list({ limit: 20 });
while (page.hasNextPage()) {
page = await page.getNextPage();
}
Use manual page handling when you need page-level metadata or want to checkpoint progress between batches.
Raw Responses
SDK methods return unwrapped data by default. Use withResponse() to inspect response metadata and the raw Response:
const result = await client.contacts.list().withResponse();
console.log(result.data.data);
console.log(result.metadata?.next);
console.log(result.status);
Use asResponse() for the raw response only:
const response = await client.topics.list().asResponse();
This is useful for debugging headers, status codes, or integration behavior.
Errors
Non-2xx responses throw typed errors:
import Sendrealm, { APIError, RateLimitError } from "@sendrealm/sdk";
try {
await client.contacts.retrieve("missing");
} catch (error) {
if (error instanceof RateLimitError) {
console.log(error.headers.get("retry-after"));
}
if (error instanceof APIError) {
console.log(error.status, error.code, error.message);
}
}
Common error categories:
- Authentication errors: check the API key and environment.
- Permission errors: check the key scope and project access.
- Validation errors: check required fields and payload shape.
- Rate limits: retry after the server-provided delay when available.
- Connection errors: check network and runtime fetch behavior.
Request Options
Most SDK methods accept request options as the final argument. Use this for per-request behavior:
await client.events.ingest(
{
event: "order.completed",
external_id: "user-123",
},
{
timeout: 30_000,
maxRetries: 2,
}
);
Use per-request options when one operation has different reliability or latency requirements than the default client.
Edge Runtime Examples
Cloudflare Workers:
import Sendrealm from "@sendrealm/sdk";
export default {
async fetch(_request: Request, env: Env) {
const client = new Sendrealm({
apiKey: env.SENDREALM_API_KEY,
});
await client.events.ingest({
event: "worker.received",
external_id: "visitor_123",
});
return new Response("ok");
},
};
Deno:
import Sendrealm from "npm:@sendrealm/sdk";
const client = new Sendrealm({
apiKey: Deno.env.get("SENDREALM_API_KEY"),
});
Bun:
import Sendrealm from "@sendrealm/sdk";
const client = new Sendrealm({
apiKey: Bun.env.SENDREALM_API_KEY,
});
Production Checklist
Before shipping:
- API key is stored in a secret manager or environment variable.
- API key is never sent to browser or mobile code.
- Sending domains are verified for email.
- Mobile SDKs are registering devices before server-side push sends.
- Event names are stable and documented.
- Event submissions use
idempotency_key where retries are possible.
- Errors are logged with status, code, and message.
- Rate limit responses are handled.
- Long-running list jobs use cursor pagination safely.
Related Pages