GenieOSdocs
SDKs

Node SDK

@genie-os/sdk — typed TypeScript client. ESM + CJS. Node 18+, Next.js, Cloud Functions, edge runtimes.

Install

npm install @genie-os/sdk
pnpm add @genie-os/sdk
yarn add @genie-os/sdk
bun add @genie-os/sdk
deno add npm:@genie-os/sdk
import { GenieOS } from '@genie-os/sdk';

// Keys: gos_live_* (production) or gos_test_* (sandbox)
const gos = new GenieOS({ apiKey: process.env.GENIEOS_API_KEY! });

The SDK is isomorphic: it works in Node 18+, edge runtimes (Cloudflare Workers, Vercel Edge), and any browser-shaped environment that exposes fetch. It has no native dependencies and ships both ESM and CJS builds.

Quick reference

gos.workspace.get();

gos.keys.list();
gos.keys.get(id);

gos.templates.list();
gos.templates.get('welcome');
gos.templates.schema('welcome');
gos.templates.create({ name: 'Welcome', key: 'welcome' });
gos.templates.compose({ prompt: 'Warm welcome for new Glow subscribers' });
gos.templates.render('welcome', { variables: { ... } });
gos.templates.send('welcome', { to: '…', variables: { ... } });

gos.sequences.list();
gos.sequences.get(keyOrId);
gos.sequences.listRuns(keyOrId);
gos.sequences.enroll(keyOrId, { contact, variables });
gos.sequences.runs.get(runId);
gos.sequences.runs.cancel(runId);

gos.events.emit({ type, contact, metadata });

gos.webhooks.list();
gos.webhooks.get(id);
gos.webhooks.create({ url, events });
gos.webhooks.update(id, { ... });
gos.webhooks.delete(id);

gos.brand.list();
gos.brand.get(id);

gos.pages.list();
gos.pages.get(idOrSlug);
gos.pages.compose(idOrSlug, { prompt });
gos.pages.publish(idOrSlug);
gos.pages.unpublish(idOrSlug);

gos.messaging.kit();
gos.messaging.catalog();
gos.messaging.send({ templateKey, to, variables });
gos.messaging.listDeliveries({ templateKey });

gos.social.listNetworks();
gos.social.refreshNetworks();
gos.social.list({ status });
gos.social.get(postId);
gos.social.create({ ... });
gos.social.schedule(postId, { scheduledAt });
gos.social.publish(postId);
gos.social.delete(postId);
gos.social.analytics(postId);

gos.marketing.strategy({ detail: 'summary' });
gos.marketing.patchStrategy({ ... });
gos.marketing.listIcps();
gos.marketing.getIcp(icpId);
gos.marketing.creationDefaults();
gos.marketing.setCreationDefaults({ ... });

gos.creations.list();
gos.creations.get(creationId);
gos.creations.spawn({ brief });
gos.creations.approveStrategy(creationId);

gos.lists.list();
gos.lists.get(listId);
gos.lists.create({ name });
gos.lists.addMembers(listId, contactIds);

gos.approvals.listPolicies();
gos.approvals.listPending();
gos.approvals.managePolicy(surfaceKind, body);
gos.approvals.decide(requestId, { decision });

gos.links.list();
gos.links.get(linkId);
gos.links.utmSuggestions({ field: 'source' });
gos.links.create({
  destinationUrl: 'https://…',
  utm: { source: 'newsletter', medium: 'email', campaign: 'summer' },
  password: 'optional-gate',
});
gos.links.update(linkId, { destinationUrl: 'https://…/v2' });
gos.links.analytics({ linkId, days: 30 });
gos.qr.create({ encodes: { kind: 'shortLink', linkId } });
gos.qr.render(qrId, { format: 'pdf', saveToAssets: true });

gos.connectors.catalog();
gos.connectors.list();

gos.audit.list({ limit: 50 });

Every mutating method takes a second options argument:

gos.templates.send(params, {
  idempotencyKey: 'order:123',
  signal: abortController.signal,
  headers: { 'X-My-Trace': traceId },
  maxRetries: 3,
});

Configuration

import { GenieOS } from '@genie-os/sdk';

const gos = new GenieOS({
  apiKey: process.env.GENIEOS_API_KEY!,   // gos_live_* or gos_test_*
  baseUrl: 'https://api.genieos.pro',     // override for self-hosted / staging
  maxRetries: 5,                              // 0 disables retries
  initialBackoffMs: 250,                      // doubled per attempt with jitter
  timeoutMs: 30_000,                          // applies per attempt
  fetch: globalThis.fetch,                    // override (e.g. node-fetch, undici)
  userAgent: 'my-app/1.4.2',                  // appended to the SDK\u2019s UA
});

Pass the bearer explicitly (apiKey). Convention across GenieOS tools:

VarPurpose
GENIEOS_API_KEYBearer token (gos_live_* or gos_test_*)
GENIEOS_API_URLOverride the API host (CLI / Python also)

Idempotency

If idempotencyKey isn\u2019t supplied, the SDK generates one by hashing the request body. Pass your own for stable, domain-shaped keys:

await gos.templates.send(
  { to, template: 'order_confirm', variables },
  { idempotencyKey: `order:${order.id}:confirm` },
);

See Idempotency.

Errors

import {
  GenieOS,
  GenieOSError,
  GenieOSAuthError,
  GenieOSValidationError,
  GenieOSNotFoundError,
  GenieOSRateLimitError,
  GenieOSServerError,
  GenieOSNetworkError,
} from '@genie-os/sdk';

try {
  await gos.templates.send(params);
} catch (err) {
  if (err instanceof GenieOSValidationError) {
    err.fields.forEach((f) => console.warn(f.path, f.code));
  } else if (err instanceof GenieOSRateLimitError) {
    await sleep(err.retryAfterSeconds * 1000);
  } else {
    throw err;
  }
}

Every error includes requestId, httpStatus, and code. See Errors.

Webhooks

import { verifyWebhook, GenieOSWebhookVerificationError } from '@genie-os/sdk';
import express from 'express';

const app = express();

app.post(
  '/genieos',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    try {
      const event = verifyWebhook({
        payload: req.body, // Buffer
        header: req.header('GenieOS-Signature')!,
        secret: process.env.GENIEOS_WEBHOOK_SECRET!,
      });
      handle(event);
      res.sendStatus(204);
    } catch (err) {
      if (err instanceof GenieOSWebhookVerificationError) {
        res.sendStatus(400);
      } else {
        res.sendStatus(500);
      }
    }
  },
);

verifyWebhook accepts an optional toleranceSeconds (default 300) to widen or tighten the replay window.

Typed templates via OpenAPI

There is no built-in codegen binary in @genie-os/sdk yet. Generate types from the live OpenAPI document instead:

curl -s https://api.genieos.pro/v1/openapi.json > openapi.json
npx openapi-typescript openapi.json -o ./src/api.types.ts

Or call gos.templates.schema('welcome') at runtime for the schema contract of a single template.

Edge runtimes

The SDK works on Vercel Edge, Cloudflare Workers, Deno, and Bun. There\u2019s no Node-specific code in the request path; the only thing that varies is how you supply the API key (env vars vs bindings).

// Cloudflare Worker
export default {
  async fetch(req: Request, env: { GENIEOS_API_KEY: string }) {
    const gos = new GenieOS({ apiKey: env.GENIEOS_API_KEY });
    await gos.events.emit({ type: 'page.viewed', contact: { external_id: '...' } });
    return new Response(null, { status: 204 });
  },
};

Tree-shaking

The SDK is structured by resource — gos.templates, gos.sequences, etc. — so bundlers can drop the resources you don\u2019t use. A typical app importing only templates.send ships ~3 KB gzipped.

On this page