Skip to content

SDKs

The SDKs wrap the HTTP API: they send your key, retry rate limits, server errors and network failures with backoff, reuse one idempotency key across a create’s retries, poll tasks until they finish and verify webhook signatures. Anything they do, you can also do with plain HTTP; see the API reference.

Terminal window
npm install @velvetapi/sdk

No dependencies; runs on Node 18+, Deno, Bun and Cloudflare Workers.

import { VelvetAPI } from "@velvetapi/sdk";
const velvet = new VelvetAPI({ apiKey: process.env.VELVET_API_KEY });
const task = await velvet.tasks.create(
{
model: "flux-3-klein",
user: "user-123",
input: { prompt: "A candid photograph of a woman with auburn hair reading on a sunlit balcony, soft morning light, 35mm film grain." },
},
{ idempotencyKey: "order-42" },
);
const done = await velvet.tasks.wait(task.id);
console.log(done.state, done.outputs.map((output) => output.url));
Method Endpoint
tasks.create({ model, input, user, webhook_url? }, { idempotencyKey? }) POST /v1/tasks
tasks.get(id) GET /v1/tasks/{id}
tasks.list({ limit?, before? }) GET /v1/tasks
tasks.cancel(id) POST /v1/tasks/{id}/cancel
tasks.wait(id, { intervalMs?, timeoutMs? }) polls GET /v1/tasks/{id}
models.list(), models.get(id) GET /v1/models, GET /v1/models/{id}
quotes.create({ model, input }) POST /v1/quotes
account.get() GET /v1/account
reports.create({ category, output_url?, task_id?, email?, details? }) POST /v1/reports

tasks.wait polls every 2 seconds for up to 10 minutes and throws WaitTimeoutError if the task is still running. Error answers throw VelvetAPIError, with status, type, message and the error’s other fields in details.

verifyWebhook checks a delivery’s signature against the raw body and returns the parsed event, or throws WebhookVerificationError:

import { verifyWebhook, WebhookVerificationError } from "@velvetapi/sdk";
try {
const event = await verifyWebhook({ body: rawBody, signature: request.headers.get("Velvet-Signature"), secret: process.env.VELVET_WEBHOOK_SECRET! });
if (event.type === "task.succeeded") console.log(event.data.outputs);
} catch (err) {
if (err instanceof WebhookVerificationError) return new Response("Invalid signature", { status: 400 });
throw err;
}
Terminal window
pip install velvetapi

Python 3.9+, with a sync client (VelvetAPI) and an asyncio one (AsyncVelvetAPI) that has the same methods as coroutines.

import os
from velvetapi import VelvetAPI
client = VelvetAPI(api_key=os.environ["VELVET_API_KEY"])
task = client.tasks.create(
model="flux-3-klein",
user="user-123",
input={"prompt": "A candid photograph of a woman with auburn hair reading on a sunlit balcony, soft morning light, 35mm film grain."},
idempotency_key="order-42",
)
done = client.tasks.wait(task["id"])
print(done["state"], [output["url"] for output in done["outputs"]])

Responses are plain dictionaries with the same fields as the HTTP API. The methods mirror the TypeScript client with Python names: tasks.get, tasks.list(limit=, before=), tasks.cancel, tasks.wait(task_id, interval=2.0, timeout=600), models.list(), models.get(), quotes.create(model=, input=), account.get() and reports.create(category=, ...). Error answers raise VelvetAPIError.

verify_webhook(body, signature, secret) returns the parsed event or raises WebhookVerificationError:

from velvetapi import WebhookVerificationError, verify_webhook
try:
event = verify_webhook(request.get_data(), request.headers.get("Velvet-Signature"), os.environ["VELVET_WEBHOOK_SECRET"])
except WebhookVerificationError:
abort(400)

Every endpoint takes and returns JSON with a bearer token, so any HTTP client works. Start from the quickstart, and see Tasks and webhooks for signature verification without a library.