Rezolve Ai SDK
The official JavaScript and TypeScript client for the Rezolve Ai v1 API.
The Rezolve Ai SDK is the official JavaScript and TypeScript client for Rezolve Ai. Use it in Node.js apps, scripts, or serverless functions to run the Contextual Enrichment Engine, manage durable jobs, and read your account usage.
Who this is for
Developers calling Rezolve Ai from their own code. If you would rather drive Rezolve Ai from a terminal, see the Rezolve Ai CLI. If you want an AI assistant to call Rezolve Ai for you, see the MCP server.
Install
npm install @rezolve-ai/sdkRenamed from @authoritas-ace/ace-sdk. The old package still resolves but is no
longer updated. The exported types moved from the Ace prefix to RezolveAi, so AceClient is now RezolveAiClient.
Create a client
import { createClient } from "@rezolve-ai/sdk";
const ace = createClient({
baseUrl: "https://ace.authoritas.com",
apiKey: process.env.ACE_API_KEY, // ace_live_... or ace_test_...
});Create a key under Settings, Developer console, Keys. See API Keys for scopes and environments.
Your first call
health() needs no key, so it is the quickest way to confirm your base URL is right.
const res = await ace.health();
console.log(res.status, res.data); // 200 { status: "ok" }How results are shaped
Every method resolves to an ApiResult<T>. Nothing throws on an API error: you get error instead of data, plus the HTTP status.
interface ApiResult<T> {
data?: T;
error?: { code: string; message: string; details?: unknown };
status: number;
}Check error yourself, or use assertOk to turn a failure into a thrown RezolveAiApiError:
import { assertOk, RezolveAiApiError } from "@rezolve-ai/sdk";
try {
const res = await ace.usage();
assertOk(res);
console.log(res.data.credits.balance); // res.data is defined past this point
} catch (err) {
if (err instanceof RezolveAiApiError) {
console.error(err.code, err.status, err.message);
}
}Contextual Enrichment Engine
Three methods, matching the three engine endpoints. Each takes a source, which is either inline products or a connected store.
// 1. Generate the eight section contextual rules for a product set.
const rules = await ace.enrichment.rules({
source: {
type: "inline",
products: [
{ id: "sku-1", title: "Merino base layer", description: "...", category: "Outdoor" },
],
},
creativityLevel: 3,
});
// 2. Generate content grounded in those rules.
const content = await ace.enrichment.content({
source: { type: "inline", products: [{ id: "sku-1", title: "Merino base layer" }] },
contentTypes: ["product-description", "meta-tags", "jsonld-schema"],
rules: rules.data,
});
// 3. Or run both steps in one call.
const pipeline = await ace.enrichment.pipeline({
source: { type: "inline", products: [{ id: "sku-1", title: "Merino base layer" }] },
contentTypes: ["product-description", "meta-tags"],
});A product needs only id and title. Extra keys you pass through (brand, price, tags, attributes) become grounding signal.
Idempotency
Write methods accept an idempotency key, so a retried request reuses the original job instead of starting a second one.
await ace.enrichment.pipeline(body, { idempotencyKey: "nightly-2026-07-29" });Jobs
A large content or pipeline request runs asynchronously and returns a job envelope. Poll it, or let the SDK poll for you.
const started = await ace.enrichment.pipeline({ source, contentTypes: ["product-description"] });
assertOk(started);
// Poll until the job reaches a terminal status (default: every 2s, 5 minute cap).
const finished = await ace.jobs.wait(started.data.id, { pollMs: 2000, timeoutMs: 300_000 });
assertOk(finished);
// Then page through the per-product output.
const results = await ace.jobs.results(started.data.id, { page: 1, pageSize: 50 });The full set:
| Method | What it does |
|---|---|
ace.jobs.list({ kind, status, storeId, page, pageSize }) | List jobs, newest first. |
ace.jobs.get(id) | Fetch one job with its status and result. |
ace.jobs.results(id, { page, pageSize }) | Paginated per-product results. |
ace.jobs.cancel(id) | Cancel a queued or running job. |
ace.jobs.wait(id, { pollMs, timeoutMs }) | Poll until terminal. Returns a TIMEOUT error if the cap elapses. |
Utilities
Fast helpers. Language detection is unbilled and the scorers are pure functions, so none of these consume credits.
await ace.utils.language({ products }); // dominant locale + confidence
await ace.utils.agenticReadiness({ products }); // per-product readiness + summary
await ace.utils.reviewQuality({ items }); // weighted overall score per itemUsage and feeds
const usage = await ace.usage();
// { env, credits: { balance, limit, periodStart, periodEnd },
// rateLimit: { limitPerMinute }, jobs: { total }, testQuota? }
await ace.feeds.list({ projectId });
await ace.feeds.get(feedId);testQuota is present only for ace_test_ keys.
Escape hatch
Any endpoint without a typed wrapper is still reachable, with auth and error handling applied:
await ace.get("/api/v1/webhooks");
await ace.post("/api/v1/webhooks", {
url: "https://example.com/hook",
events: ["enrichment.job.succeeded"],
});Next steps
- API Reference for the full endpoint list with request and response schemas
- Contextual Enrichment Engine for what the engine produces and how grounding works
- Webhooks to be notified when a job finishes instead of polling