Integrations
Connect to DEVUP AI using the official devupai npm package, version 4.0.0. TypeScript definitions, streaming with token usage, the Responses API, request IDs, automatic retries, and typed errors.
Version 4.0.0 needs Node.js 22.12 or later, carries token usage on the last stream chunk when you set stream_options: { include_usage: true }, renames the file download method to client.images.download(url), and retries transient errors by default. Every change, with before and after code, is in the migration guide.
Install the official client package from npm. The core client has no runtime dependencies and ships ESM and CommonJS builds:
npm install devupaiPass your API key as apiKey; it is required. The client does not read environment variables by itself, so read the key from your environment or secret manager and pass it in:
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});Keep API keys on the server. Never put them in browser bundles, public repositories, or client-side environment variables.
Create a completion with client.chat.completions.create. The response carries the request cost in _devup when the API returns it:
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function main() {
const response = await client.chat.completions.create({
model: "deepseek-ai/DeepSeek-V4.1-Flash-1017",
messages: [
{
role: "system",
content: "You are a concise technical assistant.",
},
{
role: "user",
content: "Explain artificial intelligence in one paragraph.",
},
],
});
console.log(response.choices[0]?.message?.content);
console.log("Cost:", response._devup?.cost_dzd, "DZD");
}
main().catch(console.error);The model ids on this page are examples. List the models available to your key with client.models.list().
Set stream: true to receive the reply as it is generated, and read the stream with for await. Add stream_options: { include_usage: true } to receive token usage: when the reply is complete, the last chunk has an empty choices array and carries usage.
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function streamResponse() {
const stream = await client.chat.completions.create({
model: "deepseek-ai/DeepSeek-V4.1-Flash-1017",
messages: [
{
role: "user",
content: "Write a short poem about Algeria.",
},
],
stream: true,
stream_options: { include_usage: true },
});
console.log("Request ID:", stream.requestId);
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
if (chunk.usage) {
console.log("\nPrompt tokens:", chunk.usage.prompt_tokens);
console.log("Completion tokens:", chunk.usage.completion_tokens);
console.log("Total tokens:", chunk.usage.total_tokens);
}
}
}
streamResponse().catch(console.error);stream.requestId, stream.warnings, and stream.response are available before you read the first chunk.stream.abort(), closes the connection.DevupAPIError with the error's code and the stream's requestId.client.responses.create() calls POST /v1/responses, the OpenAI-compatible Responses API:
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function createResponse() {
const response = await client.responses.create({
model: "deepseek-ai/DeepSeek-V4.1-Flash-1017",
instructions: "Answer in two sentences.",
input: "Describe the Sahara.",
max_output_tokens: 300,
});
console.log("Status:", response.status);
console.log("Output:", JSON.stringify(response.output, null, 2));
console.log("Tokens:", response.usage?.total_tokens);
}
createResponse().catch(console.error);With stream: true, the call resolves to a stream of typed events, such as response.output_text.delta and response.completed. Skip any event type your code does not handle.
Generate vector representations for semantic search or retrieval with client.embeddings.create. Each embedding is an array of numbers, or a base64 string when the request sets encoding_format: "base64":
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function createEmbeddings() {
const response = await client.embeddings.create({
model: "BAAI/bge-m3",
input: ["Hello world", "مرحبا بالعالم", "Bonjour le monde"],
});
const vector = response.data[0]?.embedding;
if (Array.isArray(vector)) {
console.log("Dimensions:", vector.length);
}
}
createEmbeddings().catch(console.error);client.images.download(url) fetches a generated image or video file from a URL returned by the API (for example a data[].url value) and returns the native Response, so you can read its headers and binary body:
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function downloadImage() {
const generated = await client.images.generate({
model: "black-forest-labs/FLUX-1-schnell",
prompt: "A lighthouse on the Mediterranean coast",
});
const url = generated.data[0]?.url;
if (!url) return;
const file = await client.images.download(url);
console.log("Content-Type:", file.headers.get("content-type"));
const bytes = await file.arrayBuffer();
console.log("Image bytes:", bytes.byteLength);
}
downloadImage().catch(console.error);It accepts only URLs on the API's own origin (the origin of baseURL) and does not send your API key. Any other URL, or a URL that contains a user name or password, throws a DevupAPIError before a request is sent. To download from any other URL, use fetch directly.
client.models.list(), client.models.retrieve(id), and client.balance.retrieve() send your API key. client.health.check() does not:
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function inspectAccount() {
const health = await client.health.check();
console.log("API status:", health.status);
const models = await client.models.list();
console.log("Available models:", models.data.length);
const model = await client.models.retrieve("deepseek-ai/DeepSeek-V4.1-Flash-1017");
console.log(model.id, model.type, model.supports.structured_output);
const balance = await client.balance.retrieve();
console.log("Balance:", balance.balance_dzd, "DZD");
}
inspectAccount().catch(console.error);models.retrieve(id) accepts ids that contain /; the SDK encodes them.
Every API method returns an APIPromise. Await it for the data, or call .withResponse() to also get the HTTP response, the requestId, and the warnings:
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function main() {
const { data, requestId, warnings, response } = await client.chat.completions
.create({
model: "deepseek-ai/DeepSeek-V4.1-Flash-1017",
messages: [{ role: "user", content: "Hello." }],
})
.withResponse();
console.log(data.choices[0]?.message?.content);
console.log("Request ID:", requestId);
console.log("Status:", response.status);
for (const notice of warnings) {
console.info("Notice:", notice);
}
}
main().catch(console.error);requestId is the x-request-id header; include it when you contact support. warnings lists informational notices about how the request was handled, read from the X-DEVUP-Warnings header: the request was answered. Errors carry requestId and warnings too.
Set client-level defaults such as the base URL, custom headers, retries, and the timeout:
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
baseURL: "https://api.devupai.com/v1",
headers: {
"X-Application-Name": "my-application",
},
maxRetries: 2,
timeout: 600_000,
});Every method takes request options (signal, timeout, maxRetries, headers, streamIdleTimeout) as its last argument, for one call:
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function requestWithOptions() {
const response = await client.chat.completions.create(
{
model: "deepseek-ai/DeepSeek-V4.1-Flash-1017",
messages: [
{
role: "user",
content: "Summarize Algeria in three sentences.",
},
],
},
{
timeout: 30_000,
maxRetries: 0,
headers: {
"X-Request-Source": "documentation-example",
},
},
);
console.log(response.choices[0]?.message?.content);
}
requestWithOptions().catch(console.error);The SDK manages the Authorization and Content-Type headers itself; custom headers cannot override them.
Transient errors (429, 502, 503, 504, network) are retried with backoff; set maxRetries to change it.
import DevupAI from "devupai";
// No retries for any call made with this client.
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
maxRetries: 0,
});
async function main() {
// Up to 5 retries for this call only.
const models = await client.models.list({ maxRetries: 5 });
console.log(models.data.length);
}
main().catch(console.error);timeout (default 10 minutes) is one deadline for the whole call, retries included. A timeout throws APITimeoutError.timeout covers the time until the response headers arrive. Set streamIdleTimeout to stop a stream when no data arrives for that many milliseconds.signal to cancel a call. An aborted call rejects with the signal's reason.Every API error is a DevupAPIError. The SDK throws a subclass that matches the HTTP status, so you can catch a specific case, such as RateLimitError, AuthenticationError, or APITimeoutError, or the base class:
import DevupAI, {
APITimeoutError,
AuthenticationError,
DevupAPIError,
RateLimitError,
} from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function main() {
try {
await client.chat.completions.create({
model: "deepseek-ai/DeepSeek-V4.1-Flash-1017",
messages: [
{
role: "user",
content: "Hello.",
},
],
});
} catch (error) {
if (error instanceof AuthenticationError) {
console.error("Check your API key.");
return;
}
if (error instanceof RateLimitError) {
console.error("Rate limit reached. Suggested wait (ms):", error.retryAfterMs);
return;
}
if (error instanceof APITimeoutError) {
console.error("The request timed out.");
return;
}
if (error instanceof DevupAPIError) {
console.error("Status:", error.status);
console.error("Message:", error.message);
console.error("Code:", error.code);
console.error("Param:", error.param);
console.error("Request ID:", error.requestId);
return;
}
throw error;
}
}
main().catch(console.error);| Class | Status | Notes |
|---|---|---|
| AuthenticationError | 401 | Missing or invalid API key. |
| PermissionDeniedError | 403 | The key cannot use this resource. |
| NotFoundError | 404 | For example, an unknown model. |
| ConflictError | 409 | The request could not be completed. Retry later or contact support. |
| RateLimitError | 429 | Read retryAfterMs for the suggested wait. |
| InternalServerError | 500 and up | The request could not be completed. Retry later or contact support. |
| APIConnectionError | 0 | The API could not be reached. |
| APITimeoutError | 0 | The call exceeded timeout or streamIdleTimeout. Extends APIConnectionError. |
| DevupAPIError | other | Any other status, for example 400 or 402. |
Each error carries status, message, code, param, requestId, retryAfterMs, and warnings when available. For the error codes you can act on, see the Error handling guide.
The SDK includes built-in webhook signature verification utilities (client.webhooks.verifySignature and client.webhooks.constructEvent). For webhook configuration, secret management, and payload structures, see the Webhooks documentation.
The optional, ESM-only devupai/ai export connects DEVUP AI to the Vercel AI SDK for generateText, streamText, and Next.js route handlers. Unlike the core client, its createDevupAI() reads DEVUP_API_KEY, then DEVUPAI_API_KEY, from the environment when apiKey is omitted. See the Vercel AI SDK guide.