---
title: TypeScript SDK
description: The official Clipia TypeScript SDK (npm clipia-ai 1.5.0) — install, generation queue, catalog and price estimates, webhook checks, errors and the clipia CLI.
icon: FileCode
---

The official Clipia TypeScript client is published on npm as `clipia-ai`. It runs on the global `fetch` (Node.js 18+), ships as ESM and CommonJS with types, and includes a `clipia` command for the terminal. It covers the generation queue (`queue.submit`, `queue.status`, `queue.result`), the high-level `subscribe`, the model catalog with price estimates, and account data.

<Callout type="info" title="Package and entry points">
The package is `clipia-ai`, current version 1.5.0. Import the client from `clipia-ai`; a lightweight separate entry point for webhook checks is `clipia-ai/webhook`. The only runtime dependency, `commander`, is used by the CLI. The base URL is `https://api.clipia.ai`.
</Callout>

## Quickstart [#quickstart]

<Steps>

<Step>

### Install

```bash
npm i clipia-ai
```

</Step>

<Step>

### Client

The key is a server-side secret. Keep it in the `CLIPIA_KEY` environment variable:

```ts
import { createClient } from 'clipia-ai';

const clipia = createClient({ apiKey: process.env.CLIPIA_KEY! });
```

`createClient` takes `apiKey`, an optional `baseUrl` (`https://` only), an optional `fetch` implementation, plus `maxRetries` (how many times `queue.submit` retries a transient failure, default 2; `0` disables retries) and `retryDelayMs` (the base pause between retries, default 500 ms). The key is sent in the `Authorization: Bearer` header.

</Step>

<Step>

### Generate and wait for the result

`subscribe` queues the job and polls its status until it finishes:

```ts
const out = await clipia.subscribe('nano-banana-2', {
  input: { prompt: 'a neon city in the rain, cinematic lighting' },
  onQueueUpdate: (s) => console.log(s.status),
  pollIntervalMs: 1000, // default
  timeoutMs: 600000,    // default
});

if (out.status === 'COMPLETED') {
  console.log(out.output?.images?.[0]?.url); // link to the finished image
  console.log(out.cost);                     // cost in credits
} else {
  console.error(out.error?.code, out.error?.message);
}
```

</Step>

</Steps>

`subscribe` also returns on `FAILED`, so check `status`. The client retries transient polling errors (network, `429`, `5xx`) on its own and honors `Retry-After`. If the job doesn't finish within `timeoutMs`, it throws a `ClipiaApiError` with code `subscribe_timeout`; the job keeps running and you can still fetch it by `request_id`.

## Manual queue control [#queue]

```ts
const job = await clipia.queue.submit('nano-banana-2', {
  input: { prompt: '...' },
  webhookUrl: 'https://example.com/clipia-webhook', // optional
});

const status = await clipia.queue.status(job.request_id);
const result = await clipia.queue.result(job.request_id);
// result.pending === true while the job is IN_QUEUE or IN_PROGRESS
```

Every method accepts an optional `AbortSignal` to cancel the HTTP request: `queue.status(id, signal)`, and a `signal` field in `submit` and `subscribe`. In version 1.5 the client has no per-request timeout of its own: a hung connection holds the call until your signal fires, so pass `AbortSignal.timeout(30_000)` or similar in server code.

<Callout type="info" title="Idempotency key">
The SDK generates a new `Idempotency-Key` (UUID v4) for every `queue.submit` call and retries transient failures — a network error, `429`, `500`, `502`, `503`, `504` — up to `maxRetries` times with the same key, honoring `Retry-After`: an internal retry never creates a second job. A new `submit` call in your code, however, gets a new key. To make your own retry land on the same job, pass `idempotencyKey` and reuse it on the retry — see [Idempotency](/en/docs/api-reference/idempotency).
</Callout>

## Catalog, price and account [#catalog]

```ts
const { data } = await clipia.models.list();
const model = await clipia.models.get('nano-banana-2');

const { credits } = await clipia.models.estimate('nano-banana-2', {
  prompt: 'a neon city in the rain',
});

const account = await clipia.account.get();
// { account_id, balance: { credits }, usage_30d: { requests, credits_spent } }
```

`models.list()` can include LLM models without a `slug` — see [Model catalog](/en/docs/api-reference/models). `estimate` returns the cost in credits before you run anything and charges nothing.

## Ignored parameters [#warnings]

If `input` contains a key the model will not apply (a typo, a parameter of another model), `queue.submit` and `models.estimate` accept the request as usual and return the key in `warnings` — one entry per key. When every parameter is accepted, the field is absent.

```ts
// job is the queue.submit response from the section above
for (const w of job.warnings ?? []) {
  console.warn(w.code, w.parameter, w.message);
  // unknown_parameter aspect_ration Parameter "aspect_ration" is not recognized and was ignored. …
}

// The same check before you run anything: an estimate charges nothing
const estimate = await clipia.models.estimate('nano-banana-2', { prompt: '...' });
console.log(estimate.warnings); // undefined — every parameter was accepted
```

The `InputWarning` type and the `warnings` field are described in the SDK starting with version 1.5.0. `subscribe` resolves with the generation result, which carries no warnings: call `queue.submit` or `models.estimate` to read them. The `code` values and the other rules are in [Ignored parameters](/en/docs/api-reference/submit#warnings).

## Verifying webhooks [#webhooks]

```ts
import { verifyWebhookSignature } from 'clipia-ai/webhook';

const ok = verifyWebhookSignature({
  secret: process.env.CLIPIA_WEBHOOK_SECRET!,
  headers: req.headers,
  body: rawBody, // the raw request body, before JSON.parse
  // toleranceSeconds: 300 — default
});
```

The function returns `true` or `false`. Each API key has its own webhook secret — see [Webhooks](/en/docs/api-reference/webhooks).

## Error handling [#errors]

Any non-2xx response becomes a `ClipiaApiError` with `status`, `code`, `type`, `message` and, when the server sent `Retry-After`, `retryAfterMs`. A network failure gives `status: 0` and `code: "network_error"`.

```ts
import { ClipiaApiError } from 'clipia-ai';

try {
  await clipia.queue.submit('nano-banana-2', { input: { prompt: '...' } });
} catch (e) {
  if (e instanceof ClipiaApiError) {
    console.error(e.status, e.code, e.type, e.message);
  }
}
```

Error codes are listed on the [Errors](/en/docs/api-reference/errors) page.

## CLI [#cli]

The package installs a `clipia` command. It reads the key from the `CLIPIA_KEY` variable or the `--key` flag; the flag is visible in the process list, so prefer the variable on shared machines.

```bash
export CLIPIA_KEY=clipia_test_...

npx clipia models                      # catalog
npx clipia models nano-banana-2        # one model's schema
npx clipia estimate nano-banana-2 --input '{"prompt":"a cat"}'
npx clipia generate nano-banana-2 --input '{"prompt":"a cat"}' --wait
npx clipia status <request_id>
npx clipia result <request_id>
npx clipia account
```

`generate` also takes `--webhook <url>` and `--idempotency-key <key>` (one key across re-runs of the same job), and every command takes `--base-url <url>`.

## Sandbox [#sandbox]

A key prefixed `clipia_test_` returns a canned result instantly with no credits charged — handy for tests and CI. See [Sandbox](/en/docs/getting-started/sandbox).
