Build with leading AI models. Pay in Algerian Dinar.
A TypeScript-first SDK for chat, images, embeddings, audio, video, and specialized inference through one OpenAI-compatible API.
Documentation · Dashboard · API Keys · Models · Status · npm
devupai is the official Node.js and TypeScript SDK for
DEVUP AI, an AI inference gateway built for developers
and businesses in Algeria.
It gives you one consistent interface for:
- Chat and reasoning
- Image generation and editing
- Text embeddings
- Text-to-speech and transcription
- Video generation and editing
- Specialized native inference
- Model discovery, account balance, and health operations
- Vercel AI SDK integrations
Core client: zero runtime dependencies.
Vercel AI SDK provider: available through the optionaldevupai/aiexport.
- Why DEVUP AI
- Installation
- Quick Start
- Capability Matrix
- Core SDK
- Vercel AI SDK
- Configuration
- Request Options
- TypeScript
- Error Handling
- Runtime and Security
- Models
- Get an API Key
- Resources
- License
| Capability | What it gives you |
|---|---|
| Billing in DZD | Track AI usage and costs directly in Algerian Dinar. |
| Local payment access | Top up with supported local payment methods such as Edahabia and CIB. |
| OpenAI-compatible API | Use familiar request shapes and migration patterns. |
| Multimodal inference | Access text, images, embeddings, audio, video, and specialized models from one SDK. |
| TypeScript-first contracts | Typed public requests and responses derived from the DEVUP AI OpenAPI specification. |
| Modern runtime support | Designed for Node.js 18+, browsers, and Edge-compatible environments. |
| Vercel AI SDK provider | Use generateText, streamText, route handlers, and UI streaming through devupai/ai. |
| Operational visibility | Query models, account balance, service health, and billing metadata. |
npm install devupainpm install devupai ai @ai-sdk/openai-compatible @ai-sdk/providerimport 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-Pro",
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);| Capability | SDK method | Authentication |
|---|---|---|
| Chat completions | client.chat.completions.create() |
Required |
| Image generation | client.images.generate() |
Required |
| Image editing | client.images.edit() |
Required |
| Image proxy | client.images.proxy() |
Public |
| Embeddings | client.embeddings.create() |
Required |
| Text-to-speech | client.audio.speech.create() |
Required |
| Transcription | client.audio.transcriptions.create() |
Required |
| Video generation | client.video.generations.create() |
Required |
| Video editing | client.video.edits.create() |
Required |
| Native inference | client.inference.run() |
Required |
| Model discovery | client.models.list() |
Public |
| Account balance | client.balance.retrieve() |
Required |
| Service health | client.health.check() |
Public |
| Webhook verification | client.webhooks.verifySignature() |
None (local computation) |
| Webhook construction | client.webhooks.constructEvent() |
None (local computation) |
Public operations omit the
Authorizationheader.
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function generateResponse() {
const response = await client.chat.completions.create({
model: "deepseek-ai/DeepSeek-V4-Pro",
messages: [
{
role: "user",
content: "What is retrieval-augmented generation?",
},
],
temperature: 0.4,
max_tokens: 800,
});
console.log(response.choices[0]?.message?.content);
console.log("Cost:", response._devup?.cost_dzd, "DZD");
console.log("Balance:", response._devup?.balance_dzd, "DZD");
}
generateResponse().catch(console.error);Streaming responses can contain:
- Standard OpenAI-compatible delta chunks.
- A final DEVUP billing chunk containing
_devup.
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-Pro",
messages: [
{
role: "user",
content: "Write a short poem about Algeria.",
},
],
stream: true,
});
for await (const chunk of stream) {
if ("_devup" in chunk) {
console.log("\n");
console.log("Cost:", chunk._devup.cost_dzd, "DZD");
console.log("Remaining balance:", chunk._devup.balance_dzd, "DZD");
continue;
}
process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "");
}
}
streamResponse().catch(console.error);Reasoning models may return internal thinking traces via reasoning_content on the message object, along with optional reasoning_tokens in usage.
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function runReasoning() {
// WARNING: Set max_tokens high enough to accommodate BOTH reasoning trace and final answer.
// In testing, Qwen/Qwen3-14B with max_tokens: 600 exhausted its token budget during generation,
// returning finish_reason: "length" with reasoning_content: null and a truncated answer,
// while the request was fully billed. Always check finish_reason.
const response = await client.chat.completions.create({
model: "inclusionAI/Ling-3.0-flash",
messages: [
{
role: "user",
content: "Prove whether 3571 is a prime number.",
},
],
max_tokens: 2048,
});
const choice = response.choices[0];
if (!choice) return;
// Guard against truncated generation when token budget is exhausted
if (choice.finish_reason === "length") {
console.warn("Generation truncated: token limit reached before completion.");
}
// reasoning_content is populated by some providers and null for others
if (choice.message?.reasoning_content) {
console.log("Reasoning trace:\n", choice.message.reasoning_content);
}
console.log("Answer:\n", choice.message?.content);
// reasoning_tokens is optional (returned by 1 of 5 tested providers)
if (response.usage?.reasoning_tokens !== undefined) {
console.log("Reasoning tokens:", response.usage.reasoning_tokens);
}
// prompt_tokens_details can be null or omitted depending on provider
if (response.usage?.prompt_tokens_details?.cached_tokens) {
console.log("Cached prompt tokens:", response.usage.prompt_tokens_details.cached_tokens);
}
console.log("Cost:", response._devup?.cost_dzd, "DZD");
}
runReasoning().catch(console.error);Generate an image
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function generateImage() {
const response = await client.images.generate({
model: "black-forest-labs/FLUX.1-schnell",
prompt: "A cinematic view of Algiers at sunset",
size: "1024x1024",
});
console.log(response.data[0]?.url);
console.log("Cost:", response._devup?.cost_dzd, "DZD");
}
generateImage().catch(console.error);Edit an image
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function editImage() {
const image = new Blob(["image-data"], {
type: "image/png",
});
const response = await client.images.edit({
model: "black-forest-labs/FLUX.1-schnell",
image,
prompt: "Add a red sports car in the foreground",
});
console.log(response.data[0]?.url);
}
editImage().catch(console.error);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"],
});
console.log(response.data[0]?.embedding);
console.log("Dimensions:", response.data[0]?.embedding?.length);
}
createEmbeddings().catch(console.error);Text-to-speech
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function createSpeech() {
const response = await client.audio.speech.create({
model: "kokoro",
input: "Welcome to DEVUP AI.",
voice: "af_sky",
});
console.log("Audio URL:", response.url);
console.log("Cost:", response._devup.cost_dzd, "DZD");
console.log("Balance:", response._devup.balance_dzd, "DZD");
}
createSpeech().catch(console.error);Speech-to-text
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function transcribeAudio() {
const audio = new Blob(["audio-data"], {
type: "audio/wav",
});
const transcript = await client.audio.transcriptions.create({
file: audio,
model: "openai/whisper-large-v3-turbo",
language: "ar",
response_format: "json",
});
console.log(transcript.text);
}
transcribeAudio().catch(console.error);Generate a video
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function generateVideo() {
const response = await client.video.generations.create({
model: "Wan-AI/Wan2.1-T2V-14B",
prompt: "A camel walking through the Sahara at golden hour",
width: 1280,
height: 720,
});
console.log(response.data[0]?.url);
console.log("Cost:", response._devup?.cost_dzd, "DZD");
}
generateVideo().catch(console.error);Edit a video
import DevupAI, { type VideoKeyPoint } from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function editVideo() {
const video = new Blob(["video-data"], {
type: "video/mp4",
});
const keyPoints: VideoKeyPoint[] = [
{
x: 320,
y: 240,
type: "positive",
},
];
const response = await client.video.edits.create({
model: "video-edit-model",
video,
prompt: "Enhance the subject while preserving the background",
key_points: keyPoints,
preserve_audio: true,
});
console.log(response.data[0]?.url);
}
editVideo().catch(console.error);Native inference supports specialized models whose inputs and outputs do not follow a standard OpenAI schema.
The response type defaults to unknown. Provide a generic type when your
application knows the expected result shape.
import DevupAI from "devupai";
interface RerankResponse {
results: Array<{
index: number;
score: number;
}>;
}
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
```typescript
async function rerankDocuments() {
const response = await client.rerank.create({
model: "Qwen/Qwen3-Reranker-8B",
query: "What is DEVUP AI?",
documents: [
"DEVUP AI is an AI inference gateway.",
"Algiers is the capital of Algeria.",
],
top_n: 1,
});
console.log(response.results);
}
rerankDocuments().catch(console.error);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 balance = await client.balance.retrieve();
console.log("Balance:", balance.balance_dzd, "DZD");
}
inspectAccount().catch(console.error);The image proxy returns a native Response, giving you direct access to its
headers and binary body.
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function proxyImage() {
const response = await client.images.proxy({
url: "https://example.com/image.jpg",
});
console.log("Content-Type:", response.headers.get("content-type"));
const image = await response.arrayBuffer();
console.log("Image bytes:", image.byteLength);
}
proxyImage().catch(console.error);Verify incoming webhook deliveries and construct typed event payloads.
You can import standalone helper functions directly or access them via client.webhooks.
import express from "express";
import {
constructWebhookEvent,
DevupWebhookVerificationError,
type WebhookEvent,
} from "devupai";
const app = express();
const endpointSecret = process.env.DEVUP_WEBHOOK_SECRET!;
// express.raw() is required: express.json() parses and alters the body bytes, causing verification to always fail
app.post(
"/webhook",
express.raw({ type: "application/json" }),
async (req, res) => {
const signature = req.headers["x-devup-signature"];
if (typeof signature !== "string") {
return res.status(400).send("Missing signature header");
}
try {
const event: WebhookEvent = await constructWebhookEvent({
rawBody: req.body,
signatureHeader: signature,
secret: endpointSecret,
});
if (event.status === "succeeded") {
console.log("Inference succeeded:", event.id);
console.log("Results:", event.results);
console.log("Cost:", event.cost_dzd, "DZD");
} else {
console.error("Inference failed:", event.id);
console.error("Error:", event.error.type, event.error.message);
}
res.status(200).json({ received: true });
} catch (err) {
if (err instanceof DevupWebhookVerificationError) {
console.error(`Webhook verification failed (${err.reason}):`, err.message);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
res.status(500).send("Server Error");
}
}
);
app.listen(3000, () => console.log("Webhook receiver listening on port 3000"));For workflows that prefer conditional branching over exception handling, use verifyWebhookSignature:
import { verifyWebhookSignature } from "devupai";
async function handleWebhook(rawBody: string | Uint8Array, signatureHeader: string) {
const isValid = await verifyWebhookSignature({
rawBody,
signatureHeader,
secret: process.env.DEVUP_WEBHOOK_SECRET!,
toleranceSeconds: 300,
});
if (!isValid) {
console.warn("Rejected unauthorized or expired webhook delivery");
return false;
}
const payload = JSON.parse(
typeof rawBody === "string" ? rawBody : new TextDecoder().decode(rawBody)
);
return payload;
}When constructWebhookEvent fails, it throws a DevupWebhookVerificationError with a specific reason field:
| Reason | When it fires | What to do |
|---|---|---|
malformed_header |
The X-DevUp-Signature header is missing, empty, lacks a valid t= timestamp, or contains no v1= signatures. |
Verify your web server forwards the X-DevUp-Signature header unmodified. |
timestamp_outside_tolerance |
The difference between the request timestamp t and local system time exceeds toleranceSeconds (default 300s). |
This usually indicates server clock skew rather than a forged request. Synchronize your server clock with NTP or increase toleranceSeconds. |
no_matching_signature |
None of the v1 signatures in the header match the computed HMAC over the raw body and timestamp. |
Confirm that secret matches your dashboard webhook secret, and ensure rawBody is the untouched raw byte stream (not re-serialized JSON). |
invalid_json |
The signature was successfully verified, but the payload body is not valid JSON. | Check upstream payload integrity and ensure no middle-tier proxy truncated the body. |
Always key idempotency checks on the X-DevUp-Delivery-Id header. The delivery ID is generated once and remains identical across all retry attempts. Because the t= timestamp and signature are recomputed on every attempt, a consumer keying idempotency on the signature will treat legitimate retries as new events and process duplicate results.
During a 24h secret rotation window, DEVUP AI attaches multiple v1 signatures (computed with both the previous and new secret); accepting any matching signature allows zero-downtime secret rotations without coordinated cutovers.
Use the optional devupai/ai export with the Vercel AI SDK.
npm install ai @ai-sdk/openai-compatible @ai-sdk/providerimport { generateText } from "ai";
import { createDevupAI } from "devupai/ai";
const devupai = createDevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function main() {
const { text } = await generateText({
model: devupai("deepseek-ai/DeepSeek-V4-Pro"),
prompt: "Explain neural networks in simple terms.",
});
console.log(text);
}
main().catch(console.error);import { streamText } from "ai";
import { createDevupAI } from "devupai/ai";
const devupai = createDevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function main() {
const result = streamText({
model: devupai("deepseek-ai/DeepSeek-V4-Pro"),
prompt: "Write a short story set in Algiers.",
});
for await (const text of result.textStream) {
process.stdout.write(text);
}
}
main().catch(console.error);import { streamText } from "ai";
import { createDevupAI } from "devupai/ai";
const devupai = createDevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
export async function POST(request: Request) {
const body = await request.json();
const result = streamText({
model: devupai("deepseek-ai/DeepSeek-V4-Pro"),
messages: body.messages,
});
return result.toTextStreamResponse();
}import { streamText } from "ai";
import { createDevupAI } from "devupai/ai";
const devupai = createDevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
export async function POST(request: Request) {
const body = await request.json();
const result = streamText({
model: devupai("deepseek-ai/DeepSeek-V4-Pro"),
messages: body.messages,
});
return result.toUIMessageStreamResponse();
}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",
},
});| Option | Type | Required | Default | Description |
|---|---|---|---|---|
apiKey |
string |
Yes | — | Your DEVUP AI API key. |
baseURL |
string |
No | https://api.devupai.com/v1 |
DEVUP AI API base URL. |
headers |
Record<string, string> |
No | — | Custom headers included in client requests. |
Protected authentication and content-type headers are managed by the SDK.
Resource methods accept common request options alongside their request parameters.
| Option | Type | Description |
|---|---|---|
signal |
AbortSignal | null |
Cancel a request with an external abort signal. |
timeout |
number |
Abort the request after the specified number of milliseconds. |
headers |
Record<string, string> |
Add request-specific custom headers. |
import DevupAI from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
async function requestWithTimeout() {
const response = await client.chat.completions.create({
model: "deepseek-ai/DeepSeek-V4-Pro",
messages: [
{
role: "user",
content: "Summarize Algeria in three sentences.",
},
],
timeout: 30_000,
headers: {
"X-Request-Source": "documentation-example",
},
});
console.log(response.choices[0]?.message?.content);
}
requestWithTimeout().catch(console.error);The SDK exposes typed public request and response contracts derived from the DEVUP AI OpenAPI specification, curated ergonomic request types, typed streaming chunks, and safe generics for model-dependent native inference.
import DevupAI, {
type ChatCompletion,
type ChatCompletionCreateParams,
} from "devupai";
const client = new DevupAI({
apiKey: process.env.DEVUP_API_KEY!,
});
const request: Omit<ChatCompletionCreateParams, "stream"> = {
model: "deepseek-ai/DeepSeek-V4-Pro",
messages: [
{
role: "user",
content: "Hello from TypeScript.",
},
],
};
async function typedCompletion(): Promise<ChatCompletion> {
return client.chat.completions.create(request);
}
typedCompletion()
.then((response) => {
console.log(response.choices[0]?.message?.content);
})
.catch(console.error);API and transport failures are represented by DevupAPIError.
| Property | Type | Description |
|---|---|---|
status |
number |
HTTP status code, or 0 for a network failure. |
message |
string |
Human-readable error message. |
type |
string | undefined |
API error category when available. |
code |
string | undefined |
Machine-readable API error code when available. |
requestId |
string | null |
DEVUP request identifier when returned. |
retryAfter |
string | null |
Raw Retry-After response header value. |
headers |
Record<string, string> |
Normalized response headers. |
cause |
unknown |
Original underlying error when available. |
import DevupAI, { DevupAPIError } 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-Pro",
messages: [
{
role: "user",
content: "Hello.",
},
],
});
} catch (error) {
if (error instanceof DevupAPIError) {
console.error("DEVUP API request failed");
console.error("Status:", error.status);
console.error("Message:", error.message);
console.error("Type:", error.type);
console.error("Code:", error.code);
console.error("Request ID:", error.requestId);
console.error("Retry-After:", error.retryAfter);
return;
}
throw error;
}
}
main().catch(console.error);Webhook signature and payload verification failures throw DevupWebhookVerificationError. This is not an API error, carries no HTTP status code, and represents local validation failures.
| Property | Type | Description |
|---|---|---|
name |
"DevupWebhookVerificationError" |
Error class identifier. |
message |
string |
Human-readable description of the verification failure. |
reason |
DevupWebhookVerificationErrorReason |
Machine-readable failure reason code. |
cause |
unknown |
Underlying error when available (e.g. SyntaxError on invalid JSON). |
- Node.js 18+ support
- Browser and Edge-compatible request primitives
- Webhook signature verification uses Web Crypto (
globalThis.crypto.subtle) and runs asynchronously across Node.js 18+, Edge runtimes, Cloudflare Workers, Deno, Bun, and browsers with zero dependencies - Protected authentication and content-type headers
- Public methods that omit authorization
- Timeout and external abort-signal support
- Native
Responsesupport for image proxy operations - No API key persistence performed by the SDK
Store API keys in environment variables or a server-side secret manager.
Never expose API keys in browser bundles, public repositories, or client-side environment variables.
DEVUP AI supports models across multiple modalities:
- Chat and reasoning
- Image generation and editing
- Embeddings
- Speech recognition
- Text-to-speech
- Video generation and editing
- Reranking and specialized inference
Model availability may evolve over time. The live catalog is the source of truth:
- Create an account at devupai.com.
- Open the DEVUP AI Dashboard.
- Top up your balance using a supported payment method.
- Generate an API key from the API Keys page.
- Store it securely as
DEVUP_API_KEY.
DEVUP_API_KEY=sk-devup-your-api-key| Resource | Link |
|---|---|
| Website | devupai.com |
| Documentation | docs.devupai.com |
| Dashboard | devupai.com/dashboard |
| API Keys | devupai.com/dashboard/api-keys |
| Models | devupai.com/models |
| Status | status.devupai.com |
| npm | npmjs.com/package/devupai |
The DEVUP AI Node.js SDK is released under the MIT License.
Built for Algeria. Compatible with the global AI ecosystem.
Website · Documentation · npm