Node.js Client

Use @indreamai/client for typed API access in Node.js and Edge runtimes.

Install

pnpm add @indreamai/client

Runtime Support

  • Node.js 18+ runtime
  • Edge runtimes with standard Web APIs:
    • Cloudflare Workers
    • Vercel Edge Functions
    • Deno Deploy

Initialize Client

import { IndreamClient } from '@indreamai/client'

const client = new IndreamClient({
  apiKey: process.env.INDREAM_API_KEY!,
  baseURL: 'https://api.indream.ai',
  timeout: 60_000,
  maxRetries: 2,
})

Search Illustrations

Search by keyword when you need a supported hand-drawn illustration name.

const items = await client.illustrations.search('creative')
console.log(items)

Create Export

OpenAPI enforces active export concurrency per account. If your account already has two active export tasks, exports.create returns 422 OPEN_API_EXPORT_CONCURRENCY_LIMIT_EXCEEDED.

const created = await client.exports.create({
  editorState,
  ratio: '9:16',
  scale: 0.6,
  fps: 30,
  format: 'mp4',
})

created.durationSeconds is the actual export duration. created.billedStandardSeconds is the billing unit.

Project Workflow

const project = await client.projects.create({
  title: 'Launch draft',
  editorState,
})

const asset = await client.uploads.upload(heroFile, {
  filename: 'hero.png',
  contentType: 'image/png',
  projectId: project.projectId,
})

await client.projects.sync(project.projectId, {
  editorState: {
    ...editorState,
    assets: {
      ...editorState.assets,
      hero: {
        type: 'image',
        remoteUrl: asset.fileUrl,
        remoteKey: asset.fileKey,
      },
    },
  },
})

const createdFromProject = await client.projects.createExport(project.projectId, {
  ratio: '9:16',
  scale: 0.6,
  fps: 30,
  format: 'mp4',
})

const done = await client.exports.wait(createdFromProject.taskId)
console.log(done.projectId, done.status)

Get and List

const task = await client.exports.get(created.taskId)

const page = await client.exports.list({
  pageSize: 20,
  pageCursor: null,
  createdByApiKeyId: null,
})

console.log(page.items.length, page.nextPageCursor)
console.log(page.items[0]?.createdByApiKeyId)

Wait Helper

const done = await client.exports.wait(created.taskId, {
  timeoutMs: 10 * 60 * 1000,
  pollIntervalMs: 2000,
})

wait stops at terminal statuses. It throws APIError when the terminal status is FAILED or CANCELED. Returned task snapshots include both durationSeconds and billedStandardSeconds.

Verify and Parse Webhook

import { parseExportWebhookEvent, verifyExportWebhookRequest } from '@indreamai/client'

const rawBody = await request.text()
const isValid = await verifyExportWebhookRequest({
  webhookSecret: process.env.INDREAM_WEBHOOK_SECRET!,
  rawBody,
  headers: request.headers,
  maxSkewSeconds: 300, // optional
})

if (!isValid) {
  throw new Error('Invalid webhook signature')
}

const event = parseExportWebhookEvent(JSON.parse(rawBody))
console.log(event.eventType)
console.log(
  event.task.taskId,
  event.task.status,
  event.task.durationSeconds,
  event.task.billedStandardSeconds
)

eventType values are EXPORT_STARTED, EXPORT_COMPLETED, EXPORT_FAILED. event.task has the same shape as client.exports.get(taskId) result. durationSeconds is the real export duration, while billedStandardSeconds is the billing unit. verifyExportWebhookRequest validates both signature headers and timestamp skew window.

Editor Helpers

import type { TEditorStateV1 } from '@indreamai/client'

const editorState = {
  // ...full editor state payload
} satisfies TEditorStateV1

const capabilities = await client.editor.capabilities()
const validation = await client.editor.validate(editorState)

console.log(capabilities.captionAnimations.in.map((preset) => preset.id))
console.log(validation.valid)

Error Handling

import { AuthError, RateLimitError, ValidationError } from '@indreamai/client'

try {
  await client.editor.validate(editorState)
} catch (error) {
  if (error instanceof AuthError) {
    // Invalid credentials or permission issue.
  } else if (error instanceof ValidationError) {
    // Payload is invalid and must be fixed.
  } else if (error instanceof RateLimitError) {
    // Retry with backoff.
  }
}

Resources

For source code, issues, and contributions, check out our GitHub repository. Install directly from @indreamai/client to get the latest package.

Last updated on

On this page