corent-sdk
v0.6.0
Published
Official TypeScript/JavaScript SDK for Corent — one API for AI image, video, voice, and text generation with built-in routing, failover, and exact receipts.
Maintainers
Readme
Corent SDK
One API for AI image, video, voice, and text generation. You pick a quality tier; Corent's router picks the best live model, reroutes failures, verifies the output, and returns the exact charge on every response. Failed generations are never billed.
npm install corent-sdkimport { Corent } from "corent-sdk";
const client = new Corent("co_live_..."); // get a key at https://corent.tech
const image = await client.images.generate("a lighthouse at dusk", {
tier: "premium",
aspectRatio: "9:16",
});
console.log(image.url, image.width, image.height, image.costCents);
const video = await client.videos.generate("a paper boat drifting across a puddle", {
tier: "premium",
durationS: 5,
resolution: "1080p",
});
console.log(video.url, video.resolution, video.costCents);
const speech = await client.speech.generate("Welcome to Corent.");
console.log(speech.url, speech.costCents);
const answer = await client.text.generate("Name three uses for a paperclip.", { tier: "premium" });
console.log(answer.text, answer.costCents);Make a film from one sentence
Describe the film and Corent writes the script, creates the characters once,
shoots every scene with them speaking their lines, checks quality, reshoots a
bad scene once, and joins it all into one video with sound. The price comes
first and costs nothing; the charge never goes above maxCostCents; a film
that fails or is cancelled is not billed.
const plan = await client.films.plan(
"a 50 second parody where 5 founders start a startup, know nothing, and the AI part is easy because they used Corent",
{ durationS: 50 },
);
console.log(plan.title, `$${(plan.estimatedCostCents! / 100).toFixed(2)}`);
for (const scene of plan.scenes) console.log(scene.index, scene.action, scene.dialogue);
const started = await client.films.create({
planId: plan.planId,
maxCostCents: Math.ceil(plan.estimatedCostCents! * 1.1),
});
const film = await client.films.wait(started.filmId); // checks every 60 seconds; about 15 to 30 minutes
console.log(film.videoUrl, film.costCents);A 50 second 720p film with five characters costs roughly $10 to $20.
wait() throws GenerationFailedError if the film failed and
FilmCancelledError if it was cancelled. client.films.get(id) shows the
stage (writing, casting, shooting, checking, editing),
client.films.cancel(id) stops one, and client.films.list({ customerId })
lists them.
What the SDK handles for you
- Timeout-safe renders: images submit as background jobs and are polled; a network hiccup can never lose a finished (and billed) result.
- Safe retries: every generate call carries an auto idempotency key; retries can never double-charge.
- Backoff: 429/5xx retried with
Retry-Afterrespected. - Honest receipts:
width/heightare the measured pixels of the delivered file;costCentsis the exact charge.
Pick a model yourself (direct access)
Pass model instead of tier to pin an exact model. It is never substituted:
if that model can't deliver, the call fails and you are not charged.
const image = await client.images.generate("a lighthouse at dusk", { model: "corent-flux-schnell" });
console.log(image.model); // "corent-flux-schnell", the name you asked for
await client.models(); // the menu: every model with its kind, quality and live statusEach model has one name, published as corent- + the model: corent-flux-schnell,
corent-seedance-2.0, corent-claude-opus-5. That is the spelling client.models()
lists and the one every receipt echoes back. Older spellings you may already have
hard-coded (flux-schnell, seedream-5.0-direct) keep working, the API accepts
them and answers with the published name.
When we can reach a model by more than one route, Corent serves whichever is cheapest at that moment and charges you that price, you never have to shop between near-identical entries.
Text (language models)
Every frontier lab on one key and one bill, priced per token.
const answer = await client.text.generate("Explain reserve-then-settle billing.", {
system: "Answer in two sentences.",
tier: "premium",
});
console.log(answer.text, answer.promptTokens, answer.completionTokens, answer.costCents);
// a real conversation, tool calls included
const reply = await client.text.chat(
[
{ role: "system", content: "Be terse." },
{ role: "user", content: "What's the weather?" },
],
{ model: "corent-claude-opus-5" },
);Streaming isn't wrapped here: point any OpenAI-compatible client at
https://api.corent.tech/v1 with your Corent key and it works as-is.
Keep a character or product consistent
Pass 1–4 reference images and the prompt is applied as an edit of them, so the same face, character, or product carries into a new scene.
const shot = await client.images.generate("the same woman, now on a beach", {
tier: "pro", // edit-capable models sit at premium and up
referenceImageUrls: ["https://cdn.example/her.png"],
});air and lite cannot do this and say so with a 400.
client.tiers() reports capabilities.supports_reference_images per tier.
A consistent character across shots
Make the character once as an image, then hand that image to every clip as a
reference (@Image 1 in the prompt) on corent-seedance-2.5. Ask for the last
frame back and start the next clip from it, so one shot flows into the next
without a cut. Photos of real people are rejected as references; characters
generated inside Corent are accepted.
const hero = await client.images.generate("a young sailor in a yellow raincoat, portrait, plain background", { tier: "pro" });
const shot1 = await client.videos.generate("@Image 1 pushes a rowing boat off a misty shore", {
model: "corent-seedance-2.5",
referenceImageUrls: [hero.url],
aspectRatio: "16:9", durationS: 8,
returnLastFrame: true,
});
const shot2 = await client.videos.generate("the boat drifts out and she looks back at the shore", {
imageUrl: shot1.lastFrameUrl, // the exact frame shot 1 ended on
returnLastFrame: true,
});
console.log(shot1.url, shot2.url, shot2.durationS);referenceVideoUrls (up to 10, @Video 1) and referenceAudioUrls (up to
10, @Audio 1) work the same way, and task says what to do with them:
auto, reference, edit, extend. Two helpers cover the last two:
const fixed = await client.videos.edit("Replace the red car in @Video 1 with a blue bicycle", shot1.url);
const longer = await client.videos.extend("she reaches the far bank and climbs out", shot2.url, { durationS: 5 });An edit keeps the source clip's length and shape, an extension keeps its
shape, and first/last frame (imageUrl / endImageUrl) cannot be mixed with
references; the SDK throws InvalidRequestError before anything is sent.
client.models() reports supports_reference_images, supports_video_edit,
supports_video_extend and supports_last_frame per video model.
Upload your own files
Hand Corent a file and get back a URL every other call accepts: imageUrl,
maskUrl, sourceImageUrl, referenceImageUrls. Takes a File/Blob
(browser or Node), raw bytes (Buffer, Uint8Array), or a file path (Node).
Up to 25 MB. The type comes from the File, then the filename's extension,
unless you name one.
const up = await client.upload("product.png"); // or a Blob, or bytes with { filename: "product.png" }
console.log(up.url, up.contentType, up.bytes);
await client.images.generate("the same bottle, on a beach", { tier: "pro", referenceImageUrls: [up.url] });
await client.videos.generate("the bottle slowly rotates", { imageUrl: up.url });Image tools: upscale, cut out, edit
Flat price, no tier, synchronous. The edit keeps every pixel outside the mask exactly as you sent it, which is what an ad needs when the product carries someone else's trademark.
const bigger = await client.images.upscale(up.url, { prompt: "keep the film grain" }); // prompt optional
const cutout = await client.images.removeBackground(up.url); // PNG, real transparency
const mask = await client.upload("mask.png"); // white = regenerate, black = keep
const edited = await client.images.edit(up.url, mask.url, "a red can instead of the blue one");
console.log(edited.url, edited.costCents);Tag spend by your own customer
Pass customerId (1 to 128 characters, your own id) on any generating call
and client.usage({ customerId }) reports that customer's spend alone.
Batches take a default plus a per-item override.
await client.images.generate("a fox", { tier: "air", customerId: "acct_8812" });
await client.text.generate("Summarise this.", { customerId: "acct_8812" });
await client.batches.images(
[{ prompt: "a" }, { prompt: "b", customerId: "acct_other" }],
{ customerId: "acct_8812" }, // default for every item without its own
);
await client.usage({ customerId: "acct_8812" });Batches and webhooks
// Up to 50 renders in one call. Each item bills at the normal rate.
const batch = await client.batches.images(
[{ prompt: "a fox", tier: "air" }, { prompt: "a heron", tier: "air" }],
{ idempotencyKey: "campaign-9" }, // a retry replays instead of re-billing
);
const progress = await client.batches.progress(batch.batchId);
// Or have the server deliver each result and skip polling entirely.
await client.videos.generate("a drone shot", {
tier: "premium",
webhookUrl: "https://your-server.com/webhooks/corent",
webhookSecret: "your_shared_secret", // signs every delivery
});What else you can ask for
// Repeat an image exactly, then change one thing.
const first = await client.images.generate("a fox in a library", { tier: "pro" });
const again = await client.images.generate("a fox in a library, wearing glasses", {
tier: "pro", seed: 12345, negativePrompt: "text, watermark",
});
// Four versions of one prompt in one call (four real renders, four charges).
const { images, totalCostCents } = await client.images.generateMany("a fox", 4, { tier: "air" });
// A transparent logo, at a size you choose.
await client.images.generate("a minimal fox mark", { transparent: true, width: 1024, height: 1024 });
// Video with sound, going from one picture to another.
await client.videos.generate("the camera pulls back", {
tier: "premium", audio: true,
imageUrl: "https://.../start.png", endImageUrl: "https://.../end.png",
camera: "zoom_out",
});
// Pick a voice, and shape how it reads.
const voices = await client.voices();
await client.speech.generate("Welcome aboard.", {
voiceId: voices[0].voice_id, stability: 0.3, speed: 1.1,
});
// Started something by mistake? Stop it. Costs nothing.
await client.jobs.cancel(job.id);audio: true routes only to models that actually render sound, so a silent
model can never quietly serve the request. Not every model takes every
setting: anything the chosen one could not honour comes back in
meta.unsupported_options rather than being silently ignored.
Fine-grained control
const job = await client.images.generate("...", { tier: "max_pro", wait: false });
const done = await client.jobs.wait(job.id); // resume any time
await client.tiers(); // live catalog with honest min–max price ranges
await client.models(); // direct-access menu: names, quality, live status (no price; billing is flat cost-plus)
await client.balance(); // { balanceCents, heldCents, availableCents }
await client.usage(); // what this account has spent; { customerId } narrows itEvery generate call sends an Idempotency-Key, so the SDK's own retries can
never double-charge. Pass your own idempotencyKey to make that survive a
process restart too.
Tiers: air | lite | premium | pro | max_pro, see corent.tech/pricing. Models: corent.tech/models. Docs: corent.tech/docs. MCP server for agents: corent-mcp.
