
Security News
Ruby's Bundler 4.0.18 Extends Cooldown to bundle lock and bundle cache
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.
@neuraldraft/sdk
Advanced tools
Official TypeScript SDK for the Neural Draft Project API — typed helpers for brand, content, blog, images, galleries, products, booking, and async jobs.
Official TypeScript SDK for the Neural Draft Project API. Typed helpers for brand, content, blog, images, products, booking, and async jobs.
A small, zero-dependency, typed client over the Neural Draft v1 REST API. Wraps the same auth, pagination, error, and resource conventions documented in the OpenAPI spec.
Five lines of TypeScript: read brand, list products, create a published blog post.

npm install @neuraldraft/sdk
Requires Node 20+ (uses the built-in fetch). Also works in any modern runtime that has fetch and AbortController in scope (Bun, Deno via npm: import, edge workers).
Get a project API key from the dashboard. Use a test-mode key (ndsk_test_…) in development; live keys (ndsk_live_…) bill against your project's credits.
import { NeuralDraftClient } from "@neuraldraft/sdk";
const nd = new NeuralDraftClient({
apiKey: process.env.NEURALDRAFT_API_KEY!,
});
const project = await nd.projects.me();
console.log(`Hello, ${project.name}.`);
By convention the API key lives in NEURALDRAFT_API_KEY. Never hard-code it; never commit it.
new NeuralDraftClient({
apiKey: "ndsk_live_...", // required
apiUrl: "https://api.neuraldraft.io/v1", // optional, this is the default
userAgent: "my-app/1.0.0", // optional, identifies your app in API logs
timeout: 30_000, // optional, ms; defaults to no timeout
fetch: customFetch, // optional, inject for testing or proxying
});
The client groups methods into resource namespaces that match the API tags.
projectsconst project = await nd.projects.me(); // GET /projects/me
brandconst brand = await nd.brand.get(); // GET /brand
await nd.brand.update({ colors: { primary: { hex: "#2A4A3C" } } }); // PATCH /brand
content// Read a single key
const v = await nd.content.get("hero.headline", { lang: "fr" });
console.log(v.value, v.all_locales);
// Upsert a value (creates the key if it doesn't exist). Charges 1 credit.
await nd.content.set("hero.headline", "Welcome", "en");
// Bulk-create translation keys with default values. 409 (key exists) is
// treated as "skipped" rather than failing the batch.
const r = await nd.content.bulkCreate(
{ "hero.headline": "Find your calm", "hero.cta": "Get started" },
"en",
);
console.log(r.created, r.skipped_existing);
// Async translate one key into many target locales. Charges 7 credits per
// language. Returns a JobReference — poll via nd.jobs.poll(job.id).
const job = await nd.content.translate("hero.headline", ["fr", "de"]);
components// Register editable HTML. data-translate="..." attributes become content keys;
// data-image-key="..." attributes become image slots.
const cmp = await nd.components.register({
html: '<section><h1 data-translate="hero.headline">Hello</h1></section>',
intent: "marketing_hero",
page_slug: "home",
});
console.log(cmp.id, cmp.editor_url);
const list = await nd.components.list({ page_slug: "home", page_size: 50 });
const one = await nd.components.get("cmp_2Ngd9KqLmRpW");
blogPosts// Manual draft (synchronous, 0 credits — counts against your post quota)
const post = await nd.blogPosts.create({
title: "5-minute breathwork",
content: "<p>Hi.</p>",
language_code: "en",
});
// AI generation (async — returns a Job; costs 60 credits)
const job = await nd.blogPosts.generateAi({
topic: "5-minute breathwork for anxious mornings",
word_count: 1200,
primary_keyword: "morning breathwork",
translate_to_all: true,
});
const finished = await nd.jobs.poll(job.id);
console.log("Generated:", finished.result);
// Translate an existing post to additional languages (7 credits per language)
const tjob = await nd.blogPosts.translate(post.id, ["de", "fr"]);
// Read & list
const posts = await nd.blogPosts.list({ status: "published", lang: "en" });
const one = await nd.blogPosts.get("5-minute-breathwork-for-anxious-mornings");
images// Async AI generation — costs 32 credits per image
const job = await nd.images.generate({
prompt: "Serene yoga studio at dawn",
aspect_ratio: "16:9",
key: "hero.background",
});
const finished = await nd.jobs.poll(job.id);
const { url, key } = finished.result as { url: string; key: string };
// Synchronous URL swap — 1 credit
await nd.images.replace("hero.background", { url: "https://cdn.example/img.jpg" });
// Direct file upload (multipart) — 1 credit
await nd.images.upload("logo", fileOrBlob, { filename: "logo.svg" });
productsconst list = await nd.products.list({ status: "active" });
const p = await nd.products.get(42);
const created = await nd.products.create({
name: "Cork yoga block (pair)",
price: 2999,
currency: "gbp",
type: "physical",
status: "active",
});
await nd.products.update(created.id, { price: 2799 });
bookingconst services = await nd.booking.listServices({ status: "active" });
const svc = await nd.booking.getService(12);
// Resolves an embeddable widget snippet for a service. Throws ApiError(404)
// if the service id is unknown. Both tenant id and service id are required —
// the widget script lives at /v1/widgets/booking/{tenant_id}/{service_id}.js.
const me = await nd.projects.me();
const widget = await nd.booking.getWidget(me.id, 12);
console.log(widget.embed_html); // <script src="..." async data-neuraldraft-booking="12"></script>
jobs// One-shot read
const job = await nd.jobs.get("job_2Ngd9KqLmRpW");
// Poll until terminal (completed | failed | cancelled). Throws on timeout.
const finished = await nd.jobs.poll(job.id, {
intervalMs: 1500,
timeoutMs: 5 * 60_000,
});
if (finished.status === "failed") {
console.error(finished.error);
}
// Cancel an in-flight job
await nd.jobs.cancel(job.id);
When an email is registered against more than one workspace, the central
login form needs to know which one to log into. NeuralDraftClient.tenantsForEmail
hits the central host (https://app.neuraldraft.io) without an API key and
returns the candidate workspaces:
const { tenants } = await NeuralDraftClient.tenantsForEmail("user@example.com");
for (const t of tenants) {
console.log(t.id, t.name, t.domain);
}
Every method throws ApiError on non-2xx responses or transport failures.
import { ApiError } from "@neuraldraft/sdk";
try {
await nd.blogPosts.generateAi({ topic: "..." });
} catch (err) {
if (err instanceof ApiError) {
if (err.status === 401) {
// Invalid API key — check your env config
} else if (err.status === 402) {
// Out of credits — direct user to top up at /billing
} else if (err.status === 422) {
// Validation: err.body is the API's RFC 7807 JSON; parse for `errors`
} else if (err.status === 429) {
// Rate-limited (60 req/min default) — back off and retry
} else {
throw err;
}
}
}
Branch on the API's stable machine code (in the JSON body's code field), not on the title string:
const body = JSON.parse(err.body) as { code?: string };
if (body.code === "out_of_credits") { /* … */ }
status: 0 indicates a transport failure (DNS, connection refused, timeout). path carries the API path that produced the error, useful for logs.
List endpoints return Paginated<T>:
interface Paginated<T> {
data: T[];
meta: { page: number; page_size: number; total: number };
}
Iterate page by page yourself; the SDK is intentionally low-level.
The API returns a Job reference for any operation that takes more than a couple of seconds (blog AI generation, image generation, batch translation). Jobs have a stable lifecycle:
pending → processing → completed | failed | cancelled
client.jobs.poll(id) calls GET /jobs/{id} repeatedly until the job reaches a terminal state. failed and cancelled resolve with the job (don't throw) — inspect job.status and job.error to decide what to do next.
This SDK targets the v1 stable surface of the Neural Draft API. Major version bumps mirror breaking API changes; minor versions add new methods or resources. Patch versions are bug fixes only.
npm install
npm run lint # tsc --noEmit
npm test
npm run build # → dist/
To run against a local API:
NEURALDRAFT_API_KEY=ndsk_test_xxx \
NEURALDRAFT_API_URL=http://localhost/v1 \
npx tsx scripts/smoke.ts
@neuraldraft/mcp) — for AI coding tools (Claude Code, Cursor, etc.)MIT.
FAQs
Official TypeScript SDK for the Neural Draft Project API — typed helpers for brand, content, blog, images, galleries, products, booking, and async jobs.
The npm package @neuraldraft/sdk receives a total of 1 weekly downloads. As such, @neuraldraft/sdk popularity was classified as not popular.
We found that @neuraldraft/sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.

Company News
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.