```
Pairing codes expire after 1 hour, so approve promptly. Once approved, your DMs reach the assistant and it starts replying.
### Step 5: Triage a shared group (optional)
To triage a shared support channel instead of your own DMs, add the bot to a Telegram group. With `requireMention` on, it only acts when someone mentions it, so it won't respond to every message in the group. To control who can invoke it, add your numeric Telegram user ID to `allowFrom`. The safest way to find that ID is to DM your bot and watch the logs:
```bash theme={null}
openclaw logs --follow
```
Read the `from.id` value from your message. Group chat IDs are the negative numbers that start with `-100`.
### Verify it works
Send your bot a quick message in Telegram:
```text theme={null}
hi
```
```
Hi! I'm connected and ready. Forward me a message and I'll help you triage it. 🦞
```
Everything in the sections below happens right here in this Telegram chat: you message the assistant, it runs the ZeroGPU skills, and it replies inline.
## 📨 Summarize a Message with ZeroGPU
ZeroGPU is an ultra-fast, compute-efficient inference provider for apps and agents. We run purpose-built small and nano language models across an edge-powered network for the high-volume, purpose-specific tasks your app or agent runs constantly. Plug in our OpenAI-compatible API and you're live - zero GPU infrastructure, serverless, auto-scaling by default. In this section, we will summarize a single forwarded message as an example, so you can see exactly what comes back before wiring it into your assistant's inbox workflow.
The `summarize` skill condenses a passage into a few sentences. It routes to `llama-3.1-8b-instruct-fast`. Send your assistant a message like this in your chat app:
```text theme={null}
summarize this: Hey team, quick recap of today's sync. We agreed to push the mobile
checkout redesign to the March release because the payments integration slipped a
sprint. QA flagged two blocker bugs on Android that engineering will prioritize this
week. Marketing still wants the new pricing page live before the end of the quarter,
so we will revisit scope on Thursday. Please update your tickets before standup.
```
The assistant recognizes the intent, routes to the `summarize` skill, and replies:
```
Mobile checkout redesign moved to the March release after the payments integration
slipped a sprint. QA found two Android blocker bugs for engineering to fix this week,
and marketing still wants the pricing page live by quarter-end, with scope revisited
Thursday. Everyone should update their tickets before standup.
model: llama-3.1-8b-instruct-fast · 84 tokens in / 58 out
```
Notice the trailing `model:` line: the work ran on a nano model, not your primary one. That single call is the building block for the whole inbox workflow below.
🎉 **ZeroGPU effortlessly turns a wall of text into a few clean lines in one call, providing a cheap, consistent summarization layer for AI integration!**
## 🦞 Set Up an Automatic Triage Workflow
*This is the recipe: you configure the triage workflow once by saving it to your assistant's memory, and from then on every message you forward is redacted, summarized, and labeled automatically on ZeroGPU's nano models. Set it up once, use it forever.*
The pattern is set-and-forget. Instead of describing the pipeline every time, you teach it to the assistant a single time as a standing rule. OpenClaw keeps that instruction in its memory for the channel, so future messages trigger the same redact-summarize-label workflow without you typing anything but the forward.
### Step 1: Save the workflow to memory (once)
Give your assistant the workflow as a standing instruction and ask it to remember it for this channel. You do this a single time:
```text theme={null}
Remember this as my triage workflow for this channel: whenever I forward a message,
first redact any PII, then summarize it in two or three lines, then label it by topic
(account, billing, bug, feature-request, other) and urgency (low, medium, high).
Reply with just the summary and the labels, nothing else.
```
The assistant confirms and stores the rule:
```
Saved. From now on, any message you forward to this channel will be redacted,
summarized, and labeled automatically. 🦞
```
That's the whole setup. You never send that instruction again. (Exactly how a rule is persisted depends on your OpenClaw configuration; see the [OpenClaw docs](https://docs.openclaw.ai/).)
### Step 2: Forward a message
Day to day, you do just one thing: forward the raw message, with no instruction attached.
```text theme={null}
Fwd: URGENT can't access my account -
From: Daniel Okafor
Hey, I've tried logging in like 10 times since this morning and it keeps saying
"session expired". I even reset my password twice. This is really frustrating because
I have a client demo at 2pm and all my files are locked in there. My number is
+1 206-555-0147 if it's faster to call. Account is under this email. Please help ASAP.
Also btw the mobile app just spins forever on the loading screen. Thanks, Daniel
```
### Step 3: The saved workflow runs automatically
The forward matches the rule you stored, so the assistant runs the three ZeroGPU skills in order on its own, each on a nano model. You don't send these; they are the tool calls it makes behind the scenes:
1. **`redact-pii`** (`gliner2.5-multi-v1`) masks the personal data before anything else touches the text:
```
Hey, I've tried logging in ... My number is [PHONE_NUMBER] if it's faster to call.
Account is under [EMAIL]. Also btw the mobile app just spins forever on the loading
screen. Thanks, [PERSON]
```
2. **`summarize`** (`llama-3.1-8b-instruct-fast`) condenses the masked text:
```
Customer cannot log in since this morning ("session expired") despite two password
resets, and the mobile app hangs on load. Time-sensitive: client demo at 2pm.
```
3. **`classify-structured`** (`gliner2.5-base-v1`) tags it against your label schema:
```json theme={null}
{ "topic": "account", "urgency": "high" }
```
Because redaction runs first, the customer's name, email, and phone never enter the summary, the labels, or your primary model's context.
### Step 4: The reply you get
The assistant returns the finished result in a single message:
```
🧾 Support triage
Summary: Customer cannot log in since this morning ("session expired") despite two
password resets, and the mobile app hangs on load. Time-sensitive: client demo at 2pm.
Topic: account · Urgency: high
PII redacted ✓ (name, email, phone)
💰 ZeroGPU savings so far: ≈ $3 (24,100 frontier-model tokens offloaded)
```
One forward in, one clean result out - no instruction, because the workflow already lives in the assistant's memory. Your primary model only gets pulled in for the genuinely ambiguous cases.
### Step 5: Go fully hands-off (optional)
To remove even the forward, connect a shared support channel as an OpenClaw channel. The saved workflow then fires on every message that arrives, so the channel stays triaged with no action from you at all. Check the running savings any time:
```text theme={null}
how much have I saved with ZeroGPU?
```
```
ZeroGPU cost savings
--------------------
Calls offloaded: 312
Tokens offloaded: 24,100
Estimated savings: ≈ $3.00 (baseline: claude-opus-4-8)
```
🎉 You set the workflow up once, saved it to your assistant's memory, and now every forwarded message is redacted, summarized, and labeled automatically on ZeroGPU's nano models, with the customer's personal data never reaching your primary model.
## 🌟 Highlights
This notebook has guided you through setting up and running an OpenClaw workflow with ZeroGPU for triaging forwarded messages into PII-safe, labeled summaries. You can adapt and expand this example for various other scenarios requiring fast, low-cost handling of high-volume, free-text messages.
Key tools utilized in this notebook include:
* **OpenClaw**: A self-hosted, open-source personal AI assistant that connects the chat apps you already use - Telegram, Slack, Discord, WhatsApp, iMessage, and more - to AI agents and tools through a plugin system. Here it receives the messages you forward in your channel of choice and routes the cheap summarize, classify, and redact steps to ZeroGPU instead of your primary model.
* **ZeroGPU**: An ultra-fast, compute-efficient inference provider for apps and agents. We run purpose-built small and nano language models across an edge-powered network for the high-volume, purpose-specific tasks your app or agent runs constantly. Plug in our OpenAI-compatible API and you're live - zero GPU infrastructure, serverless, auto-scaling by default.
This comprehensive setup allows you to adapt and expand the example for various scenarios requiring fast, low-cost handling of high-volume, free-text messages.
# Ad Tech
Source: https://docs.zerogpu.ai/docs/ad-tech
Edge IAB classifiers that map content to taxonomy, audience, and intent signals for programmatic advertising.
Ad tech models map content to the IAB Content Taxonomy and the audience signals that programmatic advertising runs on. ZeroGPU offers a base IAB classifier tuned for real-time categorization at the edge, an enriched variant that adds topics, keywords, and inferred intent, and a signal extractor that turns free text into structured targeting signals. Each request is shown for both the [Responses API](/api-reference/responses) and the OpenAI-compatible [Chat Completions API](/api-reference/chat-completions).
| Model | Input /1M | Output /1M | Max tokens |
| - | -: | -: | -: |
|
zlm-v1-iab-classify-edge | \$0.02 | \$0.05 | 400 |
|
zlm-v2-iab-classify-edge-enriched | \$0.05 | \$0.15 | 800 |
|
zlm-v1-iab-domain-classifier | \$0.02 | \$0.05 | 100 |
|
zlm-v1-signal-extract | \$0.04 | \$0.10 | 400 |
## zlm-v1-iab-classify-edge
> ZeroGPU's IAB classifier maps any text to the industry-standard IAB Content Taxonomy in a single, fast inference call. Each call returns categories across both the 1.0 and 2.2 taxonomies plus matched audience segments, every result scored for confidence. With support for 50+ languages, it classifies multilingual content without a translation step. At 90M parameters on ONNX, it's built for the high-volume, sub-millisecond classification that ad tech and content platforms demand, right at the edge. When you need clean category and audience signals on every request, this is the model — and when you need the full profile, reach for the enriched variant.
**References:** [Model docs](https://docs.zerogpu.ai/) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Technology has quietly reshaped the rhythm of everyday life, weaving itself into routines so seamlessly that it often goes unnoticed. From the moment a smartphone alarm wakes someone in the morning to the final glance at a glowing screen before sleep, digital systems guide communication, navigation, work, and entertainment. This transformation did not happen overnight. It emerged through decades of incremental innovation, each new tool building upon the last, until the modern world became deeply interconnected.One of the most significant changes has been the speed at which information travels.",
"model": "zlm-v1-iab-classify-edge"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-iab-classify-edge",
"messages": [
{
"role": "user",
"content": "What are the basics of exercise and physical fitness?Exercise is anything that gets your body moving. Regular exercise is one of the best things you can do for your health. It has many benefits, including improving your overall health and fitness, and reducing your risk for many chronic (long-term) diseases.Every physical fitness routine is built on a few simple ideas. These include:Make exercise a habit, as your body adapts to the type of activity you do most often. Regular practice will help you improve.Build up your activity level slowly to help you continue to get stronger, faster, or more flexible without pushing too hard all at once.Challenge yourself by lifting slightly heavier weights, adding a few more minutes to your walk, or increasing your pace."
}
]
}'
```
Returns IAB `audience` categories plus `content` matches across taxonomy versions, each with a confidence score.
```json Response theme={null}
{
"audience": [
{ "name": "Technology & Computing", "score": 0.7686 },
{ "name": "Consumer Electronics", "score": 0.7206 },
{ "name": "65-69", "score": 0.5950 }
],
"content": {
"iab_1_0": [
{ "name": "Cell Phones", "score": 0.7597 },
{ "name": "Technology & Computing", "score": 0.7387 }
],
"iab_2_2": [
{ "name": "Smartphones", "score": 0.7597 },
{ "name": "Wearable Technology", "score": 0.7387 },
{ "name": "Technology & Computing", "score": 0.7109 }
]
}
}
```
## zlm-v2-iab-classify-edge-enriched
> The enriched variant of ZeroGPU's IAB classifier turns a single inference call into a full content-intelligence profile not just a label, but everything a contextual pipeline needs to act on. Each call returns IAB categories across both the 1.0 and 2.2 taxonomies (down to tier-3), audience and interest segments, topics, keywords, and user-intent classification — all with confidence scores with edge-native, sub-millisecond speeds. With support for 50+ languages, it delivers the same full profile on multilingual content without a translation step. Built for contextual ad targeting, brand-safety scoring, publisher content categorization, and signal pipelines that need full metadata on every request.
**References:** [Model docs](https://docs.zerogpu.ai/) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Technology has quietly reshaped the rhythm of everyday life, weaving itself into routines so seamlessly that it often goes unnoticed. From the moment a smartphone alarm wakes someone in the morning to the final glance at a glowing screen before sleep, digital systems guide communication, navigation, work, and entertainment. This transformation did not happen overnight. It emerged through decades of incremental innovation, each new tool building upon the last, until the modern world became deeply interconnected.One of the most significant changes has been the speed at which information travels.",
"model": "zlm-v2-iab-classify-edge-enriched"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v2-iab-classify-edge-enriched",
"messages": [
{
"role": "user",
"content": "What are the basics of exercise and physical fitness?Exercise is anything that gets your body moving. Regular exercise is one of the best things you can do for your health. It has many benefits, including improving your overall health and fitness, and reducing your risk for many chronic (long-term) diseases.Every physical fitness routine is built on a few simple ideas. These include:Make exercise a habit, as your body adapts to the type of activity you do most often. Regular practice will help you improve.Build up your activity level slowly to help you continue to get stronger, faster, or more flexible without pushing too hard all at once.Challenge yourself by lifting slightly heavier weights, adding a few more minutes to your walk, or increasing your pace."
}
]
}'
```
In addition to scored `audience` and `content` categories, the enriched model returns taxonomy codes and parent IDs, plus `topics`, `keywords`, and an inferred `user_intent`.
```json Response theme={null}
{
"audience": [
{
"id": 687,
"parent_id": 206,
"name": "Technology & Computing",
"tier1_name": "Interest",
"tier2_name": "Technology & Computing",
"score": 0.7686
},
{
"id": 703,
"parent_id": 687,
"name": "Consumer Electronics",
"tier1_name": "Interest",
"tier2_name": "Technology & Computing",
"tier3_name": "Consumer Electronics",
"score": 0.7206
}
],
"content": {
"iab_1_0": [
{ "code": "IAB19-6", "name": "Cell Phones", "tier": 2, "parent_code": "IAB19", "score": 0.7597 },
{ "code": "IAB19", "name": "Technology & Computing", "tier": 1, "parent_code": null, "score": 0.7387 }
]
},
"topics": [
{ "name": "smartphones", "score": 0.7597 },
{ "name": "wearable technology", "score": 0.7387 },
{ "name": "technology & computing", "score": 0.7109 }
],
"keywords": ["technology", "reshaped", "everyday", "routines", "quietly", "weaving", "rhythm", "itself", "life", "into"],
"user_intent": {
"name": "mastering technology quietly reshaped rhythm everyday life",
"category": "informational",
"score": 0.5
}
}
```
## zlm-v1-iab-domain-classifier
> ZeroGPU's Domain IAB Classifier maps a raw domain name straight to the IAB Content Taxonomy in a single, fast inference call, returning content categories, topics, keywords, and user-intent signals. Because it needs only the domain as input, it reduces payload size by up to 10x compared to page-level classification workflows while still surfacing the contextual signals that bidstream enrichment, contextual targeting, and domain-level intelligence pipelines run on. At 149M parameters on ONNX, it's built for the high-volume, sub-millisecond classification that ad tech and content platforms demand, right at the edge.
**References:** [Model docs](https://docs.zerogpu.ai/) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
### Domain-level classification
Page-level classifiers like `zlm-v1-iab-classify-edge` and `zlm-v2-iab-classify-edge-enriched` take the full body of an article or page as input and map that content to the taxonomy. `zlm-v1-iab-domain-classifier` works one level up: it takes only the raw domain name (for example `nytimes.com`) and infers the categories, topics, keywords, and intent that characterize the site as a whole.
That shift has two practical effects:
* **Up to 10x smaller payloads.** You send a single hostname instead of crawling and shipping page text, which makes it well suited to bidstream enrichment, where the domain is often the only contextual signal available and per-request size matters.
* **No page fetch required.** Use it when you have the domain but not the rendered content — domain-level intelligence pipelines, allow/deny list scoring, and contextual targeting at the inventory level. When you do have the page text and need per-URL precision, reach for the page-level classifiers instead.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "nytimes.com",
"model": "zlm-v1-iab-domain-classifier"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-iab-domain-classifier",
"messages": [
{
"role": "user",
"content": "nytimes.com"
}
]
}'
```
Returns scored `content` categories across taxonomy versions plus `topics`, `keywords`, and an inferred `user_intent` for the domain.
```json Response theme={null}
{
"content": {
"iab_1_0": [
{ "name": "News", "score": 0.8124 },
{ "name": "Politics", "score": 0.6533 }
],
"iab_2_2": [
{ "name": "News and Politics", "score": 0.8124 },
{ "name": "Business and Finance", "score": 0.5980 }
]
},
"topics": [
{ "name": "news", "score": 0.8124 },
{ "name": "journalism", "score": 0.6740 },
{ "name": "current events", "score": 0.6533 }
],
"keywords": ["news", "politics", "world", "business", "opinion", "media", "journalism"],
"user_intent": {
"name": "reading news and current events",
"category": "informational",
"score": 0.5
}
}
```
## zlm-v1-signal-extract
> ZeroGPU's signal extractor turns unstructured text into structured signals that downstream systems can act on. One inference call returns topics, keywords, intent, and other contextual attributes as structured output, so content enrichment, contextual intelligence, ad targeting, agent routing, recommendation systems, and analytics pipelines all read from the same pass. At 80M parameters it is built for high-volume workloads where a general-purpose LLM is more machinery than the job needs.
**References:** [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
Pass the signal categories you want in `categories`; `max_keywords` caps how many keywords come back.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-signal-extract",
"input": "How can I pay using my credit card?",
"categories": [
"signals"
]
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-signal-extract",
"messages": [
{
"role": "user",
"content": "How can I pay using my credit card?"
}
],
"categories": [
"signals"
],
"max_keywords": 6
}'
```
The signals arrive as a JSON string in the output text. Parsed:
```json Response theme={null}
{
"keywords": [
"credit card",
"login",
"official website",
"account access"
],
"user_intent": {
"name": "pay using credit card",
"category": "navigational",
"score": 0.95
}
}
```
# Audio Models
Source: https://docs.zerogpu.ai/docs/audio
Open-weight speech-to-text and text-to-speech models on ZeroGPU, billed per minute of audio.
ZeroGPU serves two open-weight audio models on OpenAI-compatible endpoints: `whisper-tiny` for speech-to-text on [`POST /v1/audio/transcriptions`](/api-reference/audio-transcriptions), and `chatterbox-nano` for text-to-speech, with voice cloning, on [`POST /v1/audio/speech`](/api-reference/audio-speech). Authenticate with `x-api-key` or `Authorization: Bearer`, so the OpenAI SDKs work with only the base URL and API key changed.
## At a glance
| Model | Price /min | Task |
| - | -: | - |
|
whisper-tiny | \$0.02 | Speech-to-Text |
|
chatterbox-nano | \$0.01 | Text-to-Speech |
Audio is billed per minute, rounded up to the next whole minute with a one-minute minimum: uploaded audio for `whisper-tiny`, generated audio for `chatterbox-nano`. The billed length is returned in the `x-audio-duration-seconds` header.
## Model cards
whisper-tiny
Speech-to-Text39M params\$0.02 / minute
OpenAI's Whisper Tiny is the smallest model in the Whisper family of speech recognition models, at 39M parameters. It is the multilingual checkpoint: it transcribes speech in the language it was spoken…
chatterbox-nano
Text-to-SpeechVoice cloning110M params\$0.01 / minute
Resemble AI's Chatterbox Nano is a 110M-parameter English text-to-speech model built for fast, low-cost speech generation. It speaks your text in a built-in voice, or clones a speaker…
## whisper-tiny
> OpenAI's Whisper Tiny is the smallest model in the Whisper family of speech recognition models, at 39M parameters. It is the multilingual checkpoint: it transcribes speech in the language it was spoken, detecting that language on its own when you don't name it, and it can translate speech into English. Its size makes it fast and cheap enough for high-volume transcription where throughput and cost matter more than the accuracy of the larger Whisper models: voice agents, meeting notes, subtitles, podcasts, and audio indexing.
**References:** [Model card](https://huggingface.co/openai/whisper-tiny) • [License](https://github.com/openai/whisper/blob/main/LICENSE) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash cURL theme={null}
curl --location 'https://api.zerogpu.ai/v1/audio/transcriptions' \
--header 'x-api-key: YOUR_API_KEY' \
--form 'model="whisper-tiny"' \
--form 'file=@"/path/to/audio.mp3"'
```
```python OpenAI SDK theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.zerogpu.ai/v1",
api_key="YOUR_API_KEY", # sent as Authorization: Bearer
)
with open("/path/to/audio.mp3", "rb") as audio:
transcript = client.audio.transcriptions.create(
model="whisper-tiny",
file=audio,
)
print(transcript.text)
```
```json Response theme={null}
{
"text": "the quick brown fox jumps over the lazy dog."
}
```
See [Transcriptions](/api-reference/audio-transcriptions) for all fields, response formats, and limits.
## chatterbox-nano
> Resemble AI's Chatterbox Nano is a 110M-parameter English text-to-speech model built for fast, low-cost speech generation. It speaks your text in a built-in voice, or clones a speaker from a short reference clip you upload with the request, and inline tags such as `[laugh]`, `[chuckle]`, and `[cough]` add paralinguistic cues. Its compact size keeps generation cheap enough for high-volume work: voice agents, conversational AI, gaming, accessibility, audiobooks, and content creation.
**References:** [Model card](https://huggingface.co/ResembleAI/chatterbox-nano) • [License](https://github.com/resemble-ai/chatterbox/blob/master/LICENSE) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash cURL (voice cloning) theme={null}
curl --location 'https://api.zerogpu.ai/v1/audio/speech' \
--header 'x-api-key: YOUR_API_KEY' \
--form 'model="chatterbox-nano"' \
--form 'input="Testing model to generate voice. Hey how are you today?"' \
--form 'response_format="mp3"' \
--form 'seed="1234"' \
--form 'voice_sample=@"/path/to/file"' \
--output speech.mp3
```
```python OpenAI SDK theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.zerogpu.ai/v1",
api_key="YOUR_API_KEY", # sent as Authorization: Bearer
)
with client.audio.speech.with_streaming_response.create(
model="chatterbox-nano",
voice="alloy", # OpenAI voice names map to the built-in voice
input="Hello from ZeroGPU.",
response_format="mp3",
) as response:
response.stream_to_file("speech.mp3")
```
Response from a test run of the SDK request above:
```text Response theme={null}
HTTP/2 200
content-type: audio/mpeg
x-audio-duration-seconds: 1.76
```
To clone a voice, attach a 6 to 30 second reference clip as `voice_sample` in a `multipart/form-data` request, as in the cURL example. The OpenAI SDKs send JSON and can't attach a clip. See [Speech](/api-reference/audio-speech) for all fields and limits.
# Errors
Source: https://docs.zerogpu.ai/docs/batch/errors
Every HTTP status, every validation message, every JSONL error code, and how to recover.
This page is a catalog of every error code you can encounter when using the
Batch and Files APIs, what each one means, and what to do about it.
## Error response shape
All errors (other than CORS preflight) return JSON in the OpenAI-compatible
envelope:
```json theme={null}
{
"error": {
"message": "Human-readable description.",
"type": "invalid_request_error",
"code": "invalid_purpose",
"param": "purpose",
"line": 5
}
}
```
* `message` is always present.
* `type` is always present. Values mirror OpenAI's vocabulary:
`invalid_request_error`, `authentication_error`, `rate_limit_exceeded`,
`internal_error`, plus `insufficient_quota` on `429` responses.
* `code` is a machine-readable string (e.g. `invalid_purpose`,
`file_not_found`, `insufficient_quota`). `null` when not meaningful.
* `param` names the offending parameter (`"model"`, `"messages"`,
`"input_file_id"`, …) or is `null`.
* `line` is included for JSONL validation failures during
`POST /v1/batches` to point at the offending line (1-based).
Every response, success or error, also carries an `x-request-id`
response header (format `req_`). Pass it along when reporting
issues to support so the call can be located in logs.
## HTTP status codes
| Status | Meaning |
| - | - |
| `200` | Success. |
| `204` | Success with no body (CORS preflight). |
| `400` | Your request is malformed or fails validation. Fix and retry. |
| `401` | Missing `x-api-key` header. |
| `403` | Headers were supplied but credentials are invalid, inactive, or don't belong to the supplied project. |
| `404` | The resource doesn't exist, or doesn't belong to your project. Both cases return `404` to avoid leaking cross-project information. |
| `413` | Uploaded file is larger than 100 MB. |
| `429` | Rate-limit / insufficient quota. The `error.type` distinguishes: `insufficient_quota` (no balance and no free credits) vs `rate_limit_exceeded` (transient throttling). |
| `500` | Internal server error. Retry with exponential backoff; if persistent, contact support. |
**Quota errors return 429**
Catch 429 for both quota exhaustion (error.type:
"insufficient\_quota") and rate-limiting (error.type:
"rate\_limit\_exceeded"). This matches OpenAI's behaviour and works
with the official SDK's built-in retry logic.
## Common synchronous errors
### `401 Unauthorized`, missing headers
```json theme={null}
{ "error": { "message": "Missing authentication headers" } }
```
**Cause:** `x-api-key` was not sent.
**Fix:** Send the required `x-api-key` header on every request. `x-project-id`
is optional, and only needed to scope the request to a specific project.
### `403 Forbidden`, invalid credentials
```json theme={null}
{ "error": { "message": "Invalid credentials" } }
```
**Cause:** The API key doesn't exist, is inactive, or belongs to a different
project than the one in `x-project-id`.
**Fix:** Verify the key, and verify the project UUID matches.
### `429 Insufficient Quota`
```json theme={null}
{
"error": {
"message": "You exceeded your current quota, please check your plan and billing details.",
"type": "insufficient_quota",
"code": "insufficient_quota",
"param": null
}
}
```
**Cause:** Your organization has zero balance and zero free credits.
**Fix:** Top up your balance.
> **Important:** quota is checked at line-execution time. If your balance
> drops to zero **during** a batch, the remaining lines fail with
> `error.code: "insufficient_quota"` in the error file (the JSONL line's
> `error.message` includes the legacy `[legacy:http_420] ` prefix for
> forensics). The batch as a whole still transitions to `completed` once
> all lines have been accounted for.
### `404 Not Found`, file or batch
```json theme={null}
{ "error": { "message": "File file-xxx not found" } }
```
```json theme={null}
{ "error": { "message": "Batch not found: batch_xxx" } }
```
**Cause:** The ID does not exist, or it belongs to another project, or it
has been soft-deleted. The same `404` is returned in all three cases.
**Fix:** Verify the ID and the `x-project-id` you're sending.
***
## Files API errors
| Status | Code | When |
| - | - | - |
| `400` | `invalid_content_type` | Upload request was not `multipart/form-data`. |
| `400` | `invalid_multipart` | The multipart body could not be parsed. |
| `400` | `invalid_purpose` | `purpose` was anything other than `"batch"`. |
| `400` | `missing_file` | No `file` field in the multipart body. |
| `400` | `empty_file` | The uploaded file had zero bytes. |
| `400` | `invalid_limit` | List `limit` query parameter was not a positive integer. |
| `404` | `file_not_found` | File does not exist or is not accessible. |
| `413` | `file_too_large` | File exceeded 100 MB. |
| `500` | `storage_error` | Backing storage error; retry. |
***
## Batches API. `POST /v1/batches` validation errors
When you create a batch, the service streams the entire input JSONL and
validates every line **synchronously** before returning a response. Any
failure returns `400` with the offending `line` (1-based, mirroring
OpenAI's `BatchError.line`). The batch is also persisted with
`status: "failed"` and a populated `errors` list, so subsequent
`GET /v1/batches/{id}` calls can introspect what went wrong.
| `message` | Cause |
| - | - |
| `input_file_id is required` | Missing or non-string `input_file_id` field. |
| `endpoint is required` | Missing or non-string `endpoint` field. |
| `completion_window must be "24h"` | Anything other than `"24h"` was supplied. |
| `Input file not found: ` | `input_file_id` doesn't exist or isn't in this project. (404) |
| `Input file object missing: ` | DB row exists but the stored object is gone. Report to support. (404) |
| `Input file contains no JSONL lines` | Uploaded file is empty or only whitespace. |
| `Input file exceeds maximum size of 209715200 bytes` | File total > 200 MB. |
| `Input file exceeds maximum of 50000 lines` | More than 50,000 lines. |
| `Line N is not valid JSON` | Line N could not be parsed as JSON. |
| `Line N must be a JSON object` | Line N parsed as an array or primitive. |
| `Line N exceeds maximum size of 1048576 bytes` | Line N > 1 MB. |
| `Line N is missing custom_id` | Missing or non-string `custom_id`. |
| `Line N duplicates custom_id "X"` | A previous line already used custom\_id `X`. |
| `Line N method must be "POST"` | `method` (case-insensitive) was not `"POST"`. |
| `Line N is missing url` | Missing or non-string `url`. |
| `Line N url "X" is not an allowed batch endpoint` | `url` is not `/v1/chat/completions`, the only [supported batch endpoint](/docs/batch/supported-endpoints). |
| `Line N url "X" does not match the batch endpoint "Y"` | Lines in the file disagree on `url`. |
| `Line N is missing body` | `body` is not a non-empty object. |
| `Line N has stream=true; streaming is not supported in batch mode` | `body.stream === true`. |
| `endpoint "X" does not match the url "Y" used by the input file` | The `endpoint` field on the create request disagrees with what's in the file. |
Validation errors carry `line` in the JSON body so you can locate and
fix the offending line:
```json theme={null}
{
"error": {
"message": "Line 5 duplicates custom_id \"req-1\"",
"type": "invalid_request_error",
"code": "invalid_request_error",
"param": null,
"line": 5
}
}
```
***
## Errors that appear in the `error_file_id` JSONL
A line can fail **after** the batch was successfully created. Each failed
line is recorded in the error file with the line's original `custom_id` and
an `error` object. These are the codes you'll see:
| `error.code` | Triggered when | Recovery |
| - | - | - |
| `invalid_request_error` | The underlying endpoint rejected the line's body (bad shape, missing field, schema violation). Legacy prefix on `error.message`: `[legacy:http_400]` or `[legacy:http_422]`. | Fix the line's `body` and re-submit just that line. |
| `authentication_error` | The API key used to submit the batch lost permission mid-flight, was deactivated, or otherwise became unusable. Legacy: `[legacy:http_401]` / `[legacy:http_403]` / `[legacy:api_key_unavailable]`. | Verify key status; issue a new key if needed. |
| `not_found_error` | A resource referenced in the body (e.g. model ID) doesn't exist. Legacy: `[legacy:http_404]`. | Verify model IDs. |
| `request_too_large` | The line body exceeded the per-request size or token budget. Legacy: `[legacy:http_413]`. | Reduce input length. |
| `insufficient_quota` | Organization quota ran out partway through the batch. Legacy: `[legacy:http_420]` / `[legacy:http_429]`. | Top up balance and re-submit the failed lines. |
| `rate_limit_exceeded` | The endpoint throttled the line (non-quota rate limit). | Re-submit the line; transient. |
| `internal_error` | The upstream service returned 5xx on every retry, or the queue exhausted delivery attempts. Legacy: `[legacy:http_5xx]` / `[legacy:retries_exhausted]` / `[legacy:dlq_exhausted]`. | Re-submit the line; transient. |
| `batch_cancelled` | The parent batch was cancelled via `POST /v1/batches/{id}/cancel` before this line was dispatched. | The line did not run; submit a fresh batch if you still need the result. |
| `batch_expired` | The 24-hour completion window elapsed before this line was dispatched. | Submit a fresh batch with the remaining lines. |
The original ZeroGPU code is preserved as a `[legacy:] ` prefix
on `error.message` for forensics. No `error.details` field is emitted -
the relevant upstream detail (if any) is folded into the message.
***
## Recovering from failures
A batch that ends with some failures is **still** `status: "completed"`.
The pattern for handling this is:
1. Read `output_file_id` and write successful results to your data store.
2. Read `error_file_id` and partition by `error.code`:
* `invalid_request_error`, `not_found_error`, `request_too_large`:
client-side issues, log, fix the input lines, and resubmit.
* `internal_error`, `rate_limit_exceeded`: transient, resubmit as-is.
* `insufficient_quota`, `authentication_error`: operational, fix the
underlying issue first, then resubmit.
* `batch_cancelled`, `batch_expired`: the lines never ran; resubmit
them in a fresh batch.
3. Build a smaller JSONL containing only the lines you want to retry, upload,
and create a new batch.
Because `custom_id` is preserved end-to-end, retries are easy to deduplicate
into your existing data store.
***
## When to contact support
Reach out to ZeroGPU support if you see:
* Persistent `500` responses from any endpoint.
* `Input file object missing` on a file you just uploaded.
* A batch stuck in `finalizing` for more than 10 minutes.
* A batch that completes but is missing both `output_file_id` and
`error_file_id` while `request_counts.total` is non-zero.
## Next steps
The Batch object, status lifecycle, and every endpoint.
Line schemas for input, output, and error files.
First batch in under 10 minutes, auth, upload, create, download.
# Quickstart
Source: https://docs.zerogpu.ai/docs/batch/getting-started
First batch in under 10 minutes, auth, upload, create, poll, download.
This page walks through a complete batch from start to finish in both `curl`
and the Python `openai` SDK. By the end you'll have submitted 3 chat
completions through the Batch API and read the results.
## Prerequisites
| Credential | Where to find it |
| - | - |
| **API key** (`x-api-key`) | ZeroGPU dashboard → API Keys |
| **Project ID** (`x-project-id`) | ZeroGPU dashboard → Projects |
Both headers are required on every request. Missing either returns `401`.
**Keep your API key out of source control**
Store it in environment variables, secret managers, or your CI's secret
store, never commit it.
```bash theme={null}
export ZGPU_API_KEY="your-api-key"
export ZGPU_PROJECT_ID="your-project-uuid"
```
## Base URLs
| Environment | URL |
| - | - |
| Production | `https://api.zerogpu.ai` |
| Staging | `https://staging.api.zerogpu.ai` |
| Development | `https://dev.api.zerogpu.ai` |
The Batch and Files endpoints live under these hostnames:
* `POST /v1/files`, `GET /v1/files`, `GET /v1/files/{id}`, `GET /v1/files/{id}/content`, `DELETE /v1/files/{id}`
* `POST /v1/batches`, `GET /v1/batches`, `GET /v1/batches/{batch_id}`
***
## 1. Build the input JSONL
Every batch is driven by a JSONL file where each line is one inference
request:
```json theme={null}
{"custom_id": "req-1", "method": "POST", "url": "/v1/chat/completions", "body": { ... }}
```
| Field | Required | Description |
| - | - | - |
| `custom_id` | Yes | Your identifier for the request. Must be **unique within the batch**. Echoed back in the output so you can match results to inputs. |
| `method` | Yes | Must be `"POST"`. |
| `url` | Yes | Must be `/v1/chat/completions`, the only [supported batch endpoint](/docs/batch/supported-endpoints). All lines in a batch must share the same `url`. |
| `body` | Yes | The JSON body you would send to that endpoint synchronously. `"stream": true` is rejected, batches are non-streaming. |
Full schema and validation rules: [JSONL format](/docs/batch/jsonl-format).
```bash cURL theme={null}
cat > input.jsonl <<'EOF'
{"custom_id":"q-1","method":"POST","url":"/v1/chat/completions","body":{"model":"","messages":[{"role":"user","content":"What is the capital of France?"}]}}
{"custom_id":"q-2","method":"POST","url":"/v1/chat/completions","body":{"model":"","messages":[{"role":"user","content":"What is the capital of Germany?"}]}}
{"custom_id":"q-3","method":"POST","url":"/v1/chat/completions","body":{"model":"","messages":[{"role":"user","content":"What is the capital of Italy?"}]}}
EOF
```
```python Python theme={null}
import json
questions = [
("q-1", "What is the capital of France?"),
("q-2", "What is the capital of Germany?"),
("q-3", "What is the capital of Italy?"),
]
with open("input.jsonl", "w") as f:
for custom_id, question in questions:
f.write(json.dumps({
"custom_id": custom_id,
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": "",
"messages": [{"role": "user", "content": question}],
},
}) + "\n")
```
## 2. Upload the file
Send the JSONL to `POST /v1/files` with `purpose=batch`. The response
contains the `file_id` you'll reference when creating the batch.
```bash cURL theme={null}
curl -X POST https://api.zerogpu.ai/v1/files \
-H "x-api-key: $ZGPU_API_KEY" \
-H "x-project-id: $ZGPU_PROJECT_ID" \
-F purpose=batch \
-F file=@input.jsonl
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="ignored-by-zerogpu",
base_url="https://api.zerogpu.ai/v1",
default_headers={
"x-api-key": os.environ["ZGPU_API_KEY"],
"x-project-id": os.environ["ZGPU_PROJECT_ID"],
},
)
uploaded = client.files.create(
file=open("input.jsonl", "rb"),
purpose="batch",
)
print(uploaded.id) # file-abc...
```
Response:
```json theme={null}
{
"id": "file-abc123...",
"object": "file",
"bytes": 612,
"created_at": 1736290000,
"filename": "input.jsonl",
"purpose": "batch",
"status": "processed",
"expires_at": 1738882000
}
```
## 3. Create the batch
Submit the batch with the file ID, the target endpoint, and a 24-hour
completion window. The response returns immediately with
`status: "in_progress"`, actual processing is asynchronous.
```bash cURL theme={null}
curl -X POST https://api.zerogpu.ai/v1/batches \
-H "x-api-key: $ZGPU_API_KEY" \
-H "x-project-id: $ZGPU_PROJECT_ID" \
-H "content-type: application/json" \
-d '{
"input_file_id": "file-abc123...",
"endpoint": "/v1/chat/completions",
"completion_window": "24h"
}'
```
```python Python theme={null}
batch = client.batches.create(
input_file_id=uploaded.id,
endpoint="/v1/chat/completions",
completion_window="24h",
metadata={"job": "capitals-demo"},
)
print(batch.id, batch.status) # batch_01HZX... in_progress
```
Response:
```json theme={null}
{
"id": "batch_01HZX...",
"object": "batch",
"endpoint": "/v1/chat/completions",
"status": "in_progress",
"input_file_id": "file-abc123...",
"output_file_id": null,
"error_file_id": null,
"created_at": 1736290000,
"expires_at": 1736376400,
"request_counts": { "total": 3, "completed": 0, "failed": 0 }
}
```
**Validation runs at create time**
The server streams the entire input JSONL and validates every line before
responding. If anything is wrong, duplicate custom\_id, line
over 1 MB, stream: true, mismatched url, you'll
get a 400 with the offending line. Once the response
returns, the batch is durably committed.
## 4. Poll until complete
Poll `GET /v1/batches/{batch_id}` until `status` is `completed`, `expired`,
or `failed`. A 30-second interval is a reasonable default.
```bash cURL theme={null}
while true; do
RESP=$(curl -s "https://api.zerogpu.ai/v1/batches/$BATCH_ID" \
-H "x-api-key: $ZGPU_API_KEY" \
-H "x-project-id: $ZGPU_PROJECT_ID")
STATUS=$(echo "$RESP" | jq -r '.status')
echo "$RESP" | jq -c '{status, request_counts}'
case "$STATUS" in completed|failed|expired) break;; esac
sleep 30
done
```
```python Python theme={null}
import time
while batch.status not in ("completed", "failed", "expired"):
time.sleep(30)
batch = client.batches.retrieve(batch.id)
print(batch.status, batch.request_counts)
```
When `status` is `completed`, the response contains `output_file_id` (and,
if any line failed, `error_file_id`).
## 5. Download the results
Stream the output and error files via `GET /v1/files/{file_id}/content`.
```bash cURL theme={null}
curl -s "https://api.zerogpu.ai/v1/files/$OUTPUT_FILE_ID/content" \
-H "x-api-key: $ZGPU_API_KEY" \
-H "x-project-id: $ZGPU_PROJECT_ID" \
-o output.jsonl
jq -r '"\(.custom_id): \(.response.body.choices[0].message.content)"' output.jsonl
```
```python Python theme={null}
if batch.output_file_id:
data = client.files.content(batch.output_file_id).read()
with open("output.jsonl", "wb") as f:
f.write(data)
for line in data.decode().splitlines():
rec = json.loads(line)
print(rec["custom_id"], rec["response"]["body"]["choices"][0]["message"]["content"])
```
Output line shape (one per successful line, order **not preserved**, match
by `custom_id`):
```json theme={null}
{"id": "batch_req_a", "custom_id": "q-1", "response": {"status_code": 200, "request_id": "req_xyz", "body": { ... }}}
```
Error line shape (one per failed line):
```json theme={null}
{"id": "batch_req_b", "custom_id": "q-2", "response": null, "error": {"code": "invalid_request_error", "message": "[legacy:http_400] ...", "param": null}}
```
Full schemas: [JSONL format](/docs/batch/jsonl-format).
## Scale it up
The same five steps handle a real workload. This script sends 1,000 prompts
and collects the answers into a CSV, generating the JSONL from your own data,
polling once a minute, and matching results back by `custom_id`:
```python theme={null}
import csv, json, os, time
from openai import OpenAI
client = OpenAI(
api_key="ignored-by-zerogpu",
base_url="https://api.zerogpu.ai/v1",
default_headers={
"x-api-key": os.environ["ZGPU_API_KEY"],
"x-project-id": os.environ["ZGPU_PROJECT_ID"],
},
)
# 1. Write JSONL from your data (anything yielding (doc_id, prompt) tuples)
prompts = load_my_dataset() # 1000 records
with open("chat.jsonl", "w") as f:
for doc_id, prompt in prompts:
f.write(json.dumps({
"custom_id": doc_id,
"method": "POST",
"url": "/v1/chat/completions",
"body": {"model": "", "messages": [{"role": "user", "content": prompt}]},
}) + "\n")
# 2-3. Upload + create
uploaded = client.files.create(file=open("chat.jsonl", "rb"), purpose="batch")
batch = client.batches.create(
input_file_id=uploaded.id,
endpoint="/v1/chat/completions",
completion_window="24h",
)
# 4. Poll
while batch.status not in ("completed", "failed", "expired", "cancelled"):
time.sleep(60)
batch = client.batches.retrieve(batch.id)
print(f"{batch.status}: {batch.request_counts.completed}/{batch.request_counts.total}")
if batch.status != "completed":
raise SystemExit(f"Batch ended with status {batch.status}")
# 5. Download, parse, write CSV
output = client.files.content(batch.output_file_id).read().decode()
results = {
rec["custom_id"]: rec["response"]["body"]["choices"][0]["message"]["content"]
for rec in (json.loads(line) for line in output.splitlines() if line.strip())
}
with open("results.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["doc_id", "answer"])
writer.writerows(results.items())
```
For larger jobs, also read `error_file_id` and resubmit only the failed
lines, see [Errors reference](/docs/batch/errors) for the recovery pattern.
## Next steps
Exact line schema for input, output, and error files.
Body and response shape for `/v1/chat/completions`.
Status lifecycle, the full Batch object schema, and every endpoint.
Recover from failed lines without re-running the whole batch.
# Overview
Source: https://docs.zerogpu.ai/docs/batch/index
Run large workloads of AI inference asynchronously, wire-compatible with `/v1/batches` and `/v1/files`.
The Batch API processes hundreds, thousands, or up to 50,000 inference
requests at a discounted rate within a 24-hour window. It's the right
choice when you don't need a real-time response and want to avoid per-request
rate limits.
Run your first batch end to end in curl and Python: upload, create, poll, download.
The File and Batch objects, the status lifecycle, and every endpoint.
Line schemas for input, output, and error files, plus validation rules.
The one endpoint a batch line can target, with its request and response body.
Every status and error-file code, with recovery guidance.
## Quick facts
| | |
| - | - |
| **Base URL (production)** | `https://api.zerogpu.ai` |
| **Auth headers** | `x-api-key` (required), `x-project-id` (optional) |
| **Completion window** | 24 hours (fixed) |
| **Supported batch endpoint** | `/v1/chat/completions` (only) |
| **Max requests per batch** | 50,000 |
| **Max input file size** | 200 MB total, 1 MB per line |
| **Max upload size** | 100 MB |
| **File retention** | 30 days |
## When to use the Batch API
| You need… | Use |
| - | - |
| A single immediate response | The synchronous endpoint directly (e.g. `POST /v1/chat/completions`) |
| Hundreds-to-thousands of completions, can wait minutes-to-hours | The Batch API |
| To avoid per-second rate limits during a backfill | The Batch API |
| Streaming responses | The synchronous endpoint, streaming is **not** supported in batch mode |
Every endpoint also has an interactive playground under
[API Reference → Batch API](/api-reference/upload-file).
# JSONL Format
Source: https://docs.zerogpu.ai/docs/batch/jsonl-format
Mandatory line schemas for input, output, and error JSONL files.
Every batch is driven by three JSONL files:
| File | Direction | Purpose |
| - | - | - |
| **Input** | You upload it | One request per line; describes what the batch should do |
| **Output** | Service writes it | One result per successful line |
| **Error** | Service writes it | One record per failed line |
This page is the canonical specification for all three line schemas.
## Input JSONL
The input is a JSONL file (one JSON object per line, separated by `\n`). You
upload it via [`POST /v1/files`](/api-reference/upload-file)
with `purpose=batch`, then reference its ID when you call
[`POST /v1/batches`](/api-reference/create-batch).
### Line schema
```json theme={null}
{
"custom_id": "request-1",
"method": "POST",
"url": "/v1/chat/completions",
"body": { /* endpoint-specific payload */ }
}
```
| Field | Type | Required | Description |
| - | - | - | - |
| `custom_id` | string | **Yes** | Your identifier for this request. Must be non-empty and **unique within the batch**. Returned verbatim in the corresponding output or error line so you can match results to inputs. |
| `method` | string | **Yes** | HTTP method, case-insensitive. Only `POST` (any case) is accepted today. |
| `url` | string | **Yes** | Must be `/v1/chat/completions`, the [only batchable endpoint](/docs/batch/supported-endpoints). **All lines in a single batch must share the same `url`**, and it must match the `endpoint` field on the create call. |
| `body` | object | **Yes** | The request body that would be sent to the synchronous endpoint. See [Supported endpoints](/docs/batch/supported-endpoints) for the shape. The field `stream: true` is rejected. |
### Validation rules
The service performs all of the following checks at `POST /v1/batches` time
(not at upload time). Failure returns `400` with the offending `line`:
* Each line must be valid JSON (not arrays, not primitives, must be an object).
* `custom_id` non-empty string, unique across the whole batch.
* `method` is case-insensitive; the upper-cased value must equal `"POST"`.
* `url` must be exactly `/v1/chat/completions` on every line in the file.
Other ZeroGPU sync routes are rejected here.
* `body` must be a non-empty object.
* `body.stream === true` is rejected (streaming is not supported in batch
mode).
* Per-line size ≤ **1 MB**.
* Total file size ≤ **200 MB**.
* Total line count ≤ **50,000**.
* The file must contain at least one line.
### Format details
* Lines are separated by `\n` (LF). A trailing newline is allowed.
* Blank lines are skipped.
* UTF-8 encoding is required.
* The `url` value matches the `endpoint` field on the create request
**exactly**, no trailing slash, no query string, no protocol/host prefix.
### Example, chat completions
```jsonl theme={null}
{"custom_id":"req-1","method":"POST","url":"/v1/chat/completions","body":{"model":"","messages":[{"role":"user","content":"What is the capital of France?"}]}}
{"custom_id":"req-2","method":"POST","url":"/v1/chat/completions","body":{"model":"","messages":[{"role":"user","content":"What is the capital of Germany?"}]}}
{"custom_id":"req-3","method":"POST","url":"/v1/chat/completions","body":{"model":"","messages":[{"role":"user","content":"What is the capital of Italy?"}]}}
```
See [Supported endpoints](/docs/batch/supported-endpoints) for the
`/v1/chat/completions` body schema.
***
## Output JSONL
When a batch reaches `status: "completed"`, the service writes the successful
results to a file referenced by `output_file_id` on the Batch object. You
download it via
[`GET /v1/files/{file_id}/content`](/api-reference/download-file).
Only lines that received a **2xx** response from the underlying endpoint
appear in the output file. Failed lines go to the error file (see below).
The order of lines in the output file is **not guaranteed** to match the
order of lines in the input file, match results to inputs by `custom_id`.
### Line schema
```json theme={null}
{
"id": "batch_req_abc123...",
"custom_id": "request-1",
"response": {
"status_code": 200,
"request_id": "req_xyz789...",
"body": { /* the endpoint's normal response body */ }
}
}
```
| Field | Type | Description |
| - | - | - |
| `id` | string | Line-level identifier (prefix `batch_req_`). Stable across retries. |
| `custom_id` | string | Echo of the `custom_id` you supplied on the input line. |
| `response.status_code` | integer | HTTP status from the underlying endpoint (will always be 2xx in this file). |
| `response.request_id` | string \| null | The synchronous request id (`req_…`) of the underlying call to the orchestration API. Useful for cross-referencing logs. `null` if the upstream service didn't surface a request id. |
| `response.body` | object | The same JSON body the synchronous endpoint would have returned for this request. |
See [Supported endpoints](/docs/batch/supported-endpoints) for the exact
`response.body` shape (OpenAI `chat.completion`).
### Example, chat completions output
```jsonl theme={null}
{"id":"batch_req_a","custom_id":"req-1","response":{"status_code":200,"request_id":"req_xyz","body":{"id":"chatcmpl-abc","object":"chat.completion","created":1736295000,"model":"","choices":[{"index":0,"message":{"role":"assistant","content":"Paris."},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":2,"total_tokens":14},"system_fingerprint":null}}}
{"id":"batch_req_b","custom_id":"req-2","response":{"status_code":200,"request_id":"req_uvw","body":{"id":"chatcmpl-def","object":"chat.completion","created":1736295001,"model":"","choices":[{"index":0,"message":{"role":"assistant","content":"Berlin."},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":2,"total_tokens":14},"system_fingerprint":null}}}
```
### Reading the output
```python theme={null}
import json
with open("output.jsonl") as f:
for line in f:
record = json.loads(line)
custom_id = record["custom_id"]
body = record["response"]["body"]
answer = body["choices"][0]["message"]["content"]
print(f"{custom_id}: {answer}")
```
***
## Error JSONL
When a batch reaches `status: "completed"` (or `expired`) and at least one
line failed, the service writes the failures to a file referenced by
`error_file_id`. Successful lines go to the output file; the two are
disjoint.
### Line schema
```json theme={null}
{
"id": "batch_req_def456...",
"custom_id": "request-5",
"response": null,
"error": {
"code": "invalid_request_error",
"message": "[legacy:http_400] request body is invalid",
"param": "model"
}
}
```
| Field | Type | Description |
| - | - | - |
| `id` | string | Line-level identifier (prefix `batch_req_`). |
| `custom_id` | string | Echo of the `custom_id` you supplied on the input line. |
| `response` | null | Always `null` on error lines. Mirrors OpenAI's `{id, custom_id, response, error}` discriminator so SDK type-guards work unchanged. |
| `error.code` | string | OpenAI semantic error code. See the table below. |
| `error.message` | string | Human-readable description. The original ZeroGPU internal code is preserved as a `[legacy:] ` prefix on this string for forensics. |
| `error.param` | string \| null | Name of the offending parameter when known. |
Each error line carries an `error.code` (`invalid_request_error`,
`internal_error`, `batch_cancelled`, and so on). The full list, what triggers
each, and how to recover is in the [Errors reference](/docs/batch/errors).
### Example, error file
```jsonl theme={null}
{"id":"batch_req_e1","custom_id":"req-5","response":null,"error":{"code":"invalid_request_error","message":"[legacy:http_400] {\"message\":\"messages: missing required field\",\"type\":\"invalid_request_error\"}","param":null}}
{"id":"batch_req_e2","custom_id":"req-9","response":null,"error":{"code":"internal_error","message":"[legacy:retries_exhausted] Line failed after 4 attempts: orchestration-api returned 503: upstream timeout","param":null}}
{"id":"batch_req_e3","custom_id":"req-12","response":null,"error":{"code":"internal_error","message":"[legacy:dlq_exhausted] Message exhausted main-queue retries and was routed to the DLQ","param":null}}
```
### Reading the error file
```python theme={null}
import json
with open("errors.jsonl") as f:
for line in f:
record = json.loads(line)
line_id = record["id"] # batch_req_…
custom_id = record["custom_id"]
code = record["error"]["code"] # OpenAI semantic code
msg = record["error"]["message"]
print(f"FAIL {custom_id} ({line_id}) [{code}]: {msg}")
```
***
## Matching outputs and errors back to inputs
The output and error files together account for **all** lines in your input
file, but their order is not preserved and they may be split across the two
files. To reconstruct results for your dataset:
```python theme={null}
import json
results = {} # custom_id -> result-or-error
with open("output.jsonl") as f:
for line in f:
rec = json.loads(line)
results[rec["custom_id"]] = ("ok", rec["response"]["body"])
with open("errors.jsonl") as f:
for line in f:
rec = json.loads(line)
results[rec["custom_id"]] = ("err", rec["error"])
# now iterate your original inputs and look up by custom_id
```
If a `custom_id` you submitted is missing from both files, the batch is not
complete yet, re-check `status` and download again.
**Always match by custom\_id**
Output and error lines are not guaranteed to appear in input
order. Index your inputs by custom\_id in your code and look
results up by that key.
## Next steps
Body and response shape for `/v1/chat/completions`.
Full end-to-end walkthrough in curl and Python.
Every JSONL validation message and error code, with recovery guidance.
# Objects & lifecycle
Source: https://docs.zerogpu.ai/docs/batch/objects
The File and Batch objects, the batch status lifecycle, and how the two APIs fit together.
The Batch and Files APIs share one data model. You upload an input **file**,
create a **batch** that points at it, and when the batch finishes the service
writes result and error **files** back. This page describes those two objects,
the lifecycle a batch moves through, and where each endpoint lives.
For request and response details, every endpoint has an interactive page under
**API Reference**, linked from the tables below. To run a batch end to end,
start with the [Quickstart](/docs/batch/getting-started).
## Authentication
Both APIs authenticate with headers, not a bearer token:
```
x-api-key:
x-project-id:
```
Missing either header returns `401`; a key that is invalid, inactive, or does
not belong to the supplied project returns `403`; an organization with no
balance and no free credits returns `429` with `insufficient_quota`. See the
[Errors reference](/docs/batch/errors) for the complete list.
## Endpoints
The Files API stores the JSONL that drives a batch:
| Method | Path | Reference |
| - | - | - |
| `POST` | `/v1/files` | [Upload file](/api-reference/upload-file) |
| `GET` | `/v1/files` | [List files](/api-reference/list-files) |
| `GET` | `/v1/files/{file_id}` | [Retrieve file](/api-reference/retrieve-file) |
| `GET` | `/v1/files/{file_id}/content` | [Download file](/api-reference/download-file) |
| `DELETE` | `/v1/files/{file_id}` | [Delete file](/api-reference/delete-file) |
The Batches API submits and monitors the jobs:
| Method | Path | Reference |
| - | - | - |
| `POST` | `/v1/batches` | [Create batch](/api-reference/create-batch) |
| `GET` | `/v1/batches` | [List batches](/api-reference/list-batches) |
| `GET` | `/v1/batches/{batch_id}` | [Retrieve batch](/api-reference/retrieve-batch) |
| `POST` | `/v1/batches/{batch_id}/cancel` | [Cancel batch](/api-reference/cancel-batch) |
Both APIs are wire-compatible with OpenAI's `/v1/files` and `/v1/batches`, so
the official SDKs work once pointed at the ZeroGPU base URL. The ZeroGPU
specifics are: `completion_window` must be `"24h"`, `endpoint` must be
`/v1/chat/completions` (the only [batchable endpoint](/docs/batch/supported-endpoints)),
files are soft-deleted, and error files carry an `is_error` flag (below).
## The File object
Returned by upload and retrieve, and inside `data[]` on list.
```json theme={null}
{
"id": "file-abc123...",
"object": "file",
"bytes": 12345,
"created_at": 1736290000,
"filename": "input.jsonl",
"purpose": "batch",
"status": "processed",
"expires_at": 1738882000
}
```
| Field | Type | Description |
| - | - | - |
| `id` | string | File identifier, always prefixed `file-`. Legacy `file_` ids written before the prefix was normalised remain resolvable. |
| `object` | string | Always `"file"`. |
| `bytes` | integer | Size in bytes measured by the server after upload. |
| `created_at` | integer | Unix timestamp (seconds). |
| `filename` | string | The filename you uploaded, or `{file_id}.jsonl` if none was supplied. |
| `purpose` | string | `"batch"` for uploads; `"batch_output"` for both result and error files the service writes. |
| `status` | string | `"processed"` today. The wider `uploaded` / `processed` / `error` union matches OpenAI's published type for forward compatibility. |
| `expires_at` | integer \| omitted | When the file is removed. Uploads expire 30 days after upload; may be absent on server-written files. |
| `is_error` | boolean \| omitted | ZeroGPU extension. Present and `true` only on the error file referenced by `Batch.error_file_id`. OpenAI SDKs ignore it unless explicitly read. |
Output and error files are both written with `purpose: "batch_output"`; the
`is_error: true` flag is what distinguishes the error file when you
`GET /v1/files?purpose=batch_output`.
## The Batch object
Returned by create, retrieve, and cancel, and inside `data[]` on list.
```json theme={null}
{
"id": "batch_01HZX...",
"object": "batch",
"endpoint": "/v1/chat/completions",
"errors": null,
"input_file_id": "file-abc123...",
"completion_window": "24h",
"status": "in_progress",
"output_file_id": null,
"error_file_id": null,
"created_at": 1736290000,
"in_progress_at": 1736290001,
"expires_at": 1736376400,
"finalizing_at": null,
"completed_at": null,
"failed_at": null,
"expired_at": null,
"cancelling_at": null,
"cancelled_at": null,
"request_counts": { "total": 1500, "completed": 0, "failed": 0 },
"metadata": { "job": "nightly-classify" }
}
```
| Field | Type | Description |
| - | - | - |
| `id` | string | Batch identifier, prefix `batch_`. |
| `object` | string | Always `"batch"`. |
| `endpoint` | string | The endpoint every line in this batch targets. |
| `errors` | object \| null | When `status` is `failed`, holds `{ object: "list", data: [BatchError] }` describing the validation failure. Each `BatchError` is `{ code, message, line, param }`. `null` otherwise. |
| `input_file_id` | string | The `file-` id you supplied at creation. |
| `completion_window` | string | Always `"24h"`. |
| `status` | string | Lifecycle state, see below. |
| `output_file_id` | string \| null | File of successfully completed lines, populated when `status` is `completed`. Download via `GET /v1/files/{id}/content`. |
| `error_file_id` | string \| null | File of failed lines, populated when at least one line failed. Listed with `purpose: "batch_output"`, `is_error: true`. |
| `created_at` | integer | When the batch was created. |
| `in_progress_at` | integer \| null | When validation finished and processing started. |
| `expires_at` | integer | 24 hours after `created_at`; anything unfinished by then becomes `expired`. |
| `finalizing_at` | integer \| null | When all lines finished and the output files began writing. |
| `completed_at` / `failed_at` / `expired_at` / `cancelling_at` / `cancelled_at` | integer \| null | Timestamps for each terminal or transitional state; `null` until reached. |
| `request_counts` | object | `{ total, completed, failed }`. `completed + failed` equals `total` only once the batch is terminal. |
| `metadata` | object | Arbitrary JSON you supplied at creation, echoed back unchanged. Empty `{}` when omitted, never `null`. |
## Status lifecycle
```mermaid theme={null}
stateDiagram-v2
direction LR
[*] --> validating: POST /v1/batches
validating --> in_progress: JSONL OK
validating --> failed: JSONL rejected
in_progress --> finalizing: all lines processed
in_progress --> cancelling: POST /cancel
cancelling --> cancelled: drained
finalizing --> completed: outputs written
in_progress --> expired: 24 h elapsed
completed --> [*]
expired --> [*]
failed --> [*]
cancelled --> [*]
```
| Status | Meaning |
| - | - |
| `validating` | Row persisted; the JSONL is being streamed and validated synchronously. Transient. |
| `in_progress` | Validation succeeded; lines are being processed. |
| `finalizing` | All lines processed; output and error files are being written. Transient. |
| `completed` | Terminal. `output_file_id` (and `error_file_id` if any line failed) are populated. |
| `failed` | Terminal. JSONL validation rejected the input; `errors` holds the offending line(s). Still retrievable so SDKs can introspect. |
| `expired` | Terminal. The 24-hour window elapsed first. Whatever finished is in `output_file_id` / `error_file_id`; the rest is in the error file with `code: "batch_expired"`. |
| `cancelling` | Cancellation requested. Dispatched lines finish; pending lines are short-circuited to the error file with `code: "batch_cancelled"`. |
| `cancelled` | Terminal. Cancellation drained; files reflect whatever processed before the request. |
Validation is **synchronous**, processing is **asynchronous**: the create call
returns only after the JSONL passes (or fails) validation, and lines are then
worked through an internal queue. Once a batch is terminal, no further state
changes occur, so stop polling. Retrieve returns live `request_counts`; the
list endpoint may lag by a few seconds, so poll a specific batch for accurate
progress.
## Reading results
When `status` is `completed`:
* `output_file_id` is set if any line returned 2xx. Download it and match
results to inputs by `custom_id`, order is not preserved.
* `error_file_id` is set if any line failed. Partition by `error.code` to
decide what to retry.
Both files follow the same 30-day retention as your uploads, and the line
schemas live in [JSONL format](/docs/batch/jsonl-format). Deleting an input
file does not stop a running batch, the input is read at creation time. For
size and rate limits, see the [Overview](/docs/batch) quick facts.
## Next steps
Exact line schema for input, output, and error files.
Every status, validation message, and error-file code, with recovery steps.
# Supported Endpoints
Source: https://docs.zerogpu.ai/docs/batch/supported-endpoints
The only endpoint a batch line can target. Same request body, same response body, only the routing is asynchronous.
Every line in a batch input file must target `/v1/chat/completions` in the
`url` field, and the `endpoint` field on the create call must match. This
matches OpenAI's published batchable surface for this API version.
| `url` | Use case | Sync equivalent |
| - | - | - |
| `/v1/chat/completions` | OpenAI-style chat completions | `POST /v1/chat/completions` |
The request body inside each JSONL line's `body` field is the **same** body
you would send synchronously. The response in the output JSONL's
`response.body` is the **same** response the synchronous endpoint would
return.
**Other ZeroGPU endpoints are sync-only**
Internal routes like /summary, /v1/responses,
/usecase/classify/iab, and /gliner remain
reachable as synchronous calls but are not batchable.
Submitting a JSONL line with one of these url values is
rejected at create time with
"is not an allowed batch endpoint".
***
## `/v1/chat/completions`
Standard OpenAI-style chat completions. Suitable for any model that supports
chat-completion semantics.
### Request body (inside JSONL `body`)
```json theme={null}
{
"model": "",
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "What is the capital of France?" }
]
}
```
| Field | Required | Description |
| - | - | - |
| `model` | Yes | A model ID enabled for your project. |
| `messages` | Yes | Array of `{role, content}`. `role` is one of `user`, `assistant`, `system`, `tool`, `developer`. |
| `stream` | - | **Must not be `true`.** Rejected at batch creation. |
Per-model token limits apply (configured in model metadata). If input tokens
exceed the model's `max_tokens` setting, behavior depends on the model's
`error_on_max_token` flag: either the line fails with
`code: "context_length_exceeded"` (HTTP `400`), or the input is silently
truncated. Verify with your model's configuration.
### Response body (inside output JSONL `response.body`)
```json theme={null}
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1736295000,
"model": "",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Paris.",
"annotations": []
},
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 2,
"total_tokens": 14,
"prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"service_tier": "default",
"system_fingerprint": null
}
```
`system_fingerprint` is always `null` today. ZeroGPU does not yet expose
backend-determinism fingerprints. The field is present for SDK
compatibility (OpenAI's `ChatCompletion` type declares it as optional but
real OpenAI populates it on every response).
For **classification models** invoked via `/v1/chat/completions`,
`choices[0].message.content` is a JSON-stringified classification response
rather than free-form text. Parse it as JSON to extract the structured
result.
## Next steps
How to wrap each request body in a valid input JSONL line.
The Batch object, status lifecycle, and every endpoint.
End-to-end walkthrough in curl and Python.
# Get Started
Source: https://docs.zerogpu.ai/docs/edge-providers/get-started
Get your Edge Provider credentials, add the ZeroGPU Edge SDK to your app, and bring your first device online.
This guide takes you from a new account to a device serving inference on the ZeroGPU edge network.
Sign up at the [Edge Operator Portal](https://edge.zerogpu.ai/auth/sign-up), then choose **Add New App** and fill in:
| Field | What to enter |
| - | - |
| **App name** | The name of your app |
| **Website / store URL** | Your website, store listing, or Telegram `t.me` link |
| **Category** | Productivity, Utilities, Creative, Finance, News, Lifestyle, or Gaming |
| **Estimated monthly users** | Your approximate monthly active users |
| **Primary region** | Where most of your users are |
| **App types** | The platforms you'll integrate: Android, Browser, Chrome Extension, Telegram Mini App, macOS |
Accept the terms and select **Submit for approval**. Your app shows as **Pending Review**; review usually takes 24–48 hours. Once it's **Approved**, open the app in the portal to copy its **SDK key**.
The SDK key (`zgpu-sdk-…`) is for Edge Providers: it lets your app's devices join the network. It is different from the API key (`zgpu-api-…`) used to *call* the ZeroGPU API. Don't mix them up.
Pick the SDK that matches your app. Each SDK page covers requirements, setup, lifecycle, and troubleshooting.
```kotlin build.gradle.kts theme={null}
dependencies {
implementation("ai.zerogpu:android-sdk:0.3.0")
}
```
```html theme={null}
```
```bash theme={null}
npm install @zerogpu/browser-extension-sdk
npx zerogpu init
```
```html theme={null}
```
```bash theme={null}
npm install @zerogpu/worker
```
Pass your SDK key when you create the SDK. Keep it out of source control and inject it at build time.
```kotlin theme={null}
val sdk = ZeroGpuSdk(
context = applicationContext,
operatorKey = BuildConfig.ZEROGPU_OPERATOR_KEY, // "zgpu-sdk-…"
)
```
```html theme={null}
```
```js offscreen.js theme={null}
import { initZeroGpuOffscreen } from "./vendor/zerogpu/zerogpu-offscreen.js";
initZeroGpuOffscreen({ edgeOperatorKey: "zgpu-sdk-your-key" });
```
```js theme={null}
const worker = new ZeroGpuWorker({ operatorKey: ZEROGPU_OPERATOR_KEY });
```
Nothing to call: registration is automatic. When the SDK starts, it registers the device with the ZeroGPU device registry using your SDK key, downloads and verifies its assigned model, runs a warm-up inference, and opens a secure connection for tasks.
On Android and macOS, call `start()`. In browsers, Telegram Mini Apps, and Chrome extensions, the SDK starts as soon as it's initialized with your SDK key. From then on the device receives inference tasks from the network and runs them locally; you never feed it tasks or poll it.
* **SDK logs:** turn on debug logging (each SDK page shows how) and look for the device registering, loading its model, and becoming ready.
* **Portal:** check your app's status and the **Analytics** page in the [Edge Operator Portal](https://edge.zerogpu.ai). Apps serving traffic show as **Active/Earning**.
A connected device only receives work when the network needs it, so it may sit ready for a while before its first task.
**Tell your users.** Before the SDK starts, show your users the End User Disclosure from the Edge Operator Portal, word for word, with your app's name, and get their agreement. Give them a way to turn resource sharing off.
## Choose your SDK
`ai.zerogpu:android-sdk` for Android apps.
Script tag for websites; npm package for Chrome extensions.
One script tag in your Mini App.
`@zerogpu/worker` for Electron desktop apps.
# Edge Providers
Source: https://docs.zerogpu.ai/docs/edge-providers/index
Connect compatible devices and applications to ZeroGPU and contribute idle compute to distributed AI inference across the ZeroGPU network.
Become an Edge Provider by connecting compatible devices and applications to ZeroGPU. Contribute compute from idle devices and make that capacity available for distributed AI inference across the ZeroGPU network.
You add a ZeroGPU Edge SDK to an app you already ship. While your users run the app, their device becomes an inference node: it downloads a small model, registers with the network, and serves inference tasks locally. ZeroGPU handles routing, model assignment, and verification; you don't run any servers.
## Edge SDKs
Connect supported Android devices to the ZeroGPU edge network.
Contribute compute from websites and Chrome extensions running in supported browsers.
Connect Telegram Mini Apps to ZeroGPU and contribute available device compute to the edge network.
Connect supported Apple Silicon devices to the ZeroGPU edge network.
## How it works
Register your app in the [Edge Operator Portal](https://edge.zerogpu.ai) and submit it for approval.
Once your app is approved, copy its SDK key (`zgpu-sdk-…`) from the portal.
Add the SDK for your platform and start it with your SDK key. Devices register themselves automatically.
Devices running your app serve inference tasks. Track activity and earnings in the portal.
Set up your first Edge Provider integration.
# Android
Source: https://docs.zerogpu.ai/docs/edge-providers/sdk/android
Turn devices running your Android app into ZeroGPU edge inference nodes with the ZeroGPU Android SDK.
## Overview
The ZeroGPU Android SDK (`ai.zerogpu:android-sdk`) turns the devices running your app into on-device inference nodes on the ZeroGPU network. Once started, it registers the device, downloads the model the network assigns, and serves inference tasks locally with ONNX Runtime (and a bundled llama.cpp for GGUF models).
The SDK follows your app's lifecycle: it contributes compute while the app is in the foreground and disconnects when the app goes to the background.
## Requirements
| Requirement | Value |
| - | - |
| **Android version** | Android 8.0+ (`minSdk 26`); built against `compileSdk 36` |
| **Language** | Kotlin with coroutines |
| **ABIs** | `arm64-v8a` (physical devices) and `x86_64` (emulators) |
| **Credentials** | An SDK key (`zgpu-sdk-…`) from the [Edge Operator Portal](https://edge.zerogpu.ai) |
The SDK's manifest declares `INTERNET` and `ACCESS_NETWORK_STATE` and sets `android:largeHeap="true"`. These merge into your app automatically.
## Installation
Make sure Maven Central is a repository:
```kotlin settings.gradle.kts theme={null}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
```
Add the dependency to your app module:
```kotlin build.gradle.kts theme={null}
dependencies {
implementation("ai.zerogpu:android-sdk:0.3.0")
}
```
The SDK bundles native libraries (ONNX Runtime and llama.cpp). Add this to the `android { }` block so duplicate copies of `libc++_shared.so` don't fail the build:
```kotlin build.gradle.kts theme={null}
android {
packaging {
jniLibs {
useLegacyPackaging = true
pickFirsts += setOf("**/libc++_shared.so")
}
}
}
```
Using Expo / React Native? Install the wrapper instead: `npx expo install @zerogpu/expo-android-sdk`, add `"@zerogpu/expo-android-sdk"` to your app config plugins, and run `npx expo prebuild`.
## Initialization
Create **one** `ZeroGpuSdk` for your whole app, typically in `Application.onCreate()`. The base URL and environment default to production, so you only pass your SDK key:
```kotlin theme={null}
import ai.zerogpu.android.sdk.ZeroGpuSdk
class MyApp : Application() {
lateinit var zeroGpu: ZeroGpuSdk
override fun onCreate() {
super.onCreate()
zeroGpu = ZeroGpuSdk(
context = this,
operatorKey = BuildConfig.ZEROGPU_OPERATOR_KEY, // "zgpu-sdk-…"
)
zeroGpu.start()
}
}
```
Optional constructor parameters:
| Parameter | Default | Description |
| - | - | - |
| `enableLogs` | `false` | Write the SDK's logcat output. Turn on while integrating. |
| `enableTelemetry` | `true` | Send lifecycle and error events to ZeroGPU. |
| `resourcePolicy` | `ResourcePolicy()` | Local limits: `maxModelBytes`, `memoryBudgetFraction`, `disableGuardrails`. |
| `listener` | `null` | A `ZeroGpuListener` for lifecycle callbacks (see [Device lifecycle](#device-lifecycle)). |
| `customParams` | `emptyMap()` | Up to three reporting slots, `cust_param1`–`cust_param3`. Values only; no personal data. |
## Authentication
The SDK authenticates with your **SDK key** (`zgpu-sdk-…`), passed as `operatorKey`. Don't hard-code it. Put it in `local.properties` (git-ignored) and expose it through `BuildConfig`:
```kotlin build.gradle.kts theme={null}
import java.util.Properties
val localProps = Properties().apply {
rootProject.file("local.properties").takeIf { it.exists() }?.inputStream()?.use { load(it) }
}
android {
defaultConfig {
buildConfigField(
"String",
"ZEROGPU_OPERATOR_KEY",
"\"${localProps.getProperty("zerogpu.operatorKey", "")}\"",
)
}
buildFeatures { buildConfig = true }
}
```
```properties local.properties theme={null}
# never commit
zerogpu.operatorKey=zgpu-sdk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
## Register device
Registration is automatic. After `start()`, while the app is in the foreground, the SDK:
1. Registers the device with the ZeroGPU device registry using your SDK key.
2. Downloads its assigned model(s), verifies them, and caches them on device. Models are only re-downloaded when they change.
3. Runs a warm-up inference.
4. Opens a WebSocket and advertises the device as ready.
## Start contributing compute
Call `start()` once. From then on the device manages itself: it follows the app in and out of the foreground, reconnects after network drops, and serves whatever tasks the network sends. You don't poll it or feed it tasks.
## Stop / pause
```kotlin theme={null}
zeroGpu.stop()
```
`stop()` tears everything down: it closes the connection, unloads models, and cancels in-flight work. There is no separate pause call; to pause, call `stop()`, and call `start()` again to resume.
Going to the background already pauses contribution: the SDK closes its connection and reconnects when the app returns to the foreground.
## Device lifecycle
| State | What's happening |
| - | - |
| **Stopped** | Created but not started, or torn down by `stop()`. |
| **Registering** | Registering the device with the network. |
| **Loading models** | Downloading, verifying, and warming up models (first registration only). |
| **Ready** | Connected and waiting for tasks. |
| **Processing** | Running inference tasks. |
| **Reconnecting** | Recovering from a network drop, with backoff. |
| **Backgrounded** | App is in the background; the connection is deliberately closed. |
Before downloading models, the SDK checks free memory and storage, and blocks downloads when the battery is below 20% and the device isn't charging.
Subscribe to lifecycle changes with a `ZeroGpuListener`. Callbacks arrive on a background thread:
```kotlin theme={null}
val listener = object : ZeroGpuListener {
override fun onDegraded(reason: String) { /* resource pressure; contribution limited */ }
override fun onRecovered() { /* back to normal */ }
override fun onShutdown(reason: String) { /* the SDK stopped itself */ }
}
```
## Example integration
```kotlin MainActivity.kt theme={null}
import ai.zerogpu.android.sdk.ZeroGpuSdk
class MainActivity : ComponentActivity() {
private val sdk = ZeroGpuSdk(
context = this,
operatorKey = BuildConfig.ZEROGPU_OPERATOR_KEY, // "zgpu-sdk-…"
// baseUrl defaults to https://devices.zerogpu.ai
// env defaults to "production"
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...your UI...
sdk.start()
}
override fun onDestroy() {
sdk.stop()
super.onDestroy()
}
}
```
To confirm the device is online, construct the SDK with `enableLogs = true`, run the app in the foreground, and watch logcat:
```bash theme={null}
adb logcat -s ZeroGpuSdk:* ZeroGpuWebSocket:* ModelDownloader:*
```
Once you see `status":"idle"` and `WebSocket ready for tasks`, the device is serving the network.
## Troubleshooting
| Symptom | Likely cause / fix |
| - | - |
| `Register failed: HTTP 401/403` | Wrong or inactive SDK key. Check the key in the Edge Operator Portal. |
| Never reaches `ready for tasks` | The app isn't in the foreground, or there's no network. The connection closes in the background by design. |
| Device is ready but serves no tasks | The network hasn't needed it yet; work depends on demand. Keep the app running. |
| No SDK lines in logcat | Logging is off by default. Pass `enableLogs = true`. |
| Build error: duplicate `libc++_shared.so` | Add the `packaging { jniLibs { … } }` block from [Installation](#installation). |
| Native model won't load on some devices | Only `arm64-v8a` and `x86_64` are shipped. Use an `arm64` device or an `x86_64` emulator. |
# macOS
Source: https://docs.zerogpu.ai/docs/edge-providers/sdk/macos
Turn Macs running your Electron desktop app into ZeroGPU edge inference nodes with @zerogpu/worker.
## Overview
`@zerogpu/worker` turns the Macs running your desktop app into compute nodes on the ZeroGPU network. It runs in its own background process (an Electron [utility process](https://www.electronjs.org/docs/latest/api/utility-process)), registers the Mac, downloads its assigned model, and serves inference tasks locally. There are no servers for you to run.
Unlike the browser and Android SDKs, the worker doesn't watch battery, sleep, or window focus. It keeps serving until you stop it, so **your app decides when it runs**. The recommended policy below runs it while your app is open and the Mac is on power.
## Requirements
| Requirement | Value |
| - | - |
| **App shell** | Electron 29 or newer (Node.js 20+). Other shells that can ship Node.js 20+ also work; see [Other app shells](#other-app-shells). |
| **Hardware** | Apple Silicon (`arm64`) or Intel (`x64`) Mac |
| **Disk** | About 100 MB per assigned ONNX model (GGUF models: 2–5 GB), plus about 140 MB of native runtimes in your app bundle |
| **Credentials** | An SDK key (`zgpu-sdk-…`) from the [Edge Operator Portal](https://edge.zerogpu.ai) |
## Installation
```bash theme={null}
npm install @zerogpu/worker
```
This adds the worker and its native inference runtimes (ONNX Runtime, and llama.cpp with Metal on Apple Silicon for GGUF models). The worker must ship as a real dependency in your packaged app's `node_modules`; don't bundle it into your main-process code.
## Initialization
Create `zerogpu-worker.mjs` next to your main-process code. It starts the worker in a utility process with a free loopback port and a per-launch token, keeps its state in your app's data directory, and stops it cleanly:
```js zerogpu-worker.mjs theme={null}
import { app, utilityProcess } from "electron";
import { randomBytes } from "node:crypto";
import { createWriteStream, mkdirSync } from "node:fs";
import { createRequire } from "node:module";
import { createServer } from "node:net";
import { join } from "node:path";
const require = createRequire(import.meta.url);
/** Ask the OS for a free loopback port. */
function findFreePort() {
return new Promise((resolve, reject) => {
const probe = createServer();
probe.once("error", reject);
probe.listen(0, "127.0.0.1", () => {
const { port } = probe.address();
probe.close(() => resolve(port));
});
});
}
export class ZeroGpuWorker {
#child = null;
#log = null;
#exited = null;
#starting = null;
#port = 0;
#token = "";
constructor({ operatorKey, environment = "production", logLevel = "warn", onExit }) {
this.operatorKey = operatorKey;
this.environment = environment;
this.logLevel = logLevel;
this.onExit = onExit;
}
get running() {
return this.#child !== null;
}
/** Start the worker. Idempotent; safe to call repeatedly. */
start() {
this.#starting ??= this.#spawn().finally(() => {
this.#starting = null;
});
return this.#starting;
}
async #spawn() {
if (this.#child) return;
const stateDir = join(app.getPath("userData"), "zerogpu");
mkdirSync(stateDir, { recursive: true });
this.#port = await findFreePort();
this.#token = randomBytes(24).toString("hex");
const child = utilityProcess.fork(require.resolve("@zerogpu/worker/cli"), [], {
serviceName: "ZeroGPU Worker",
stdio: "pipe",
env: {
...process.env,
ZG_OPERATOR_KEY: this.operatorKey,
ZG_ENV: this.environment,
ZG_LOCAL_API_PORT: String(this.#port),
ZG_LOCAL_API_TOKEN: this.#token,
ZG_MODELS_DIR: join(stateDir, "models"),
ZG_DATA_DIR: join(stateDir, "data"),
ZG_MAX_CONCURRENCY: "1",
ZG_LOG_LEVEL: this.logLevel,
},
});
this.#log ??= createWriteStream(join(app.getPath("logs"), "zerogpu-worker.log"), { flags: "a" });
child.stdout?.pipe(this.#log, { end: false });
child.stderr?.pipe(this.#log, { end: false });
this.#exited = new Promise((resolve) => {
child.once("exit", (code) => {
if (this.#child === child) this.#child = null;
this.onExit?.(code);
resolve(code);
});
});
this.#child = child;
}
/** Worker health: lifecycle status, model states, served/network counters. */
async status() {
if (!this.#child) return { running: false, ready: false };
try {
const res = await fetch(`http://127.0.0.1:${this.#port}/healthz`, {
signal: AbortSignal.timeout(2000),
});
return { running: true, ...(await res.json()) };
} catch {
return { running: true, ready: false, status: "starting" };
}
}
/** Stop the worker: it leaves the network cleanly, then exits (≤ 5 s). */
async stop(timeoutMs = 7000) {
await this.#starting;
const child = this.#child;
if (!child) return;
this.#child = null;
child.kill(); // SIGTERM → graceful shutdown
await Promise.race([this.#exited, new Promise((resolve) => setTimeout(resolve, timeoutMs))]);
}
}
```
The worker is configured entirely through environment variables:
| Variable | Set to | Why |
| - | - | - |
| `ZG_OPERATOR_KEY` | your SDK key | Joins your fleet. Required. |
| `ZG_ENV` | `production` | Use `staging` or `develop` only if ZeroGPU gave you access. |
| `ZG_LOCAL_API_PORT` | a free port | The local API, bound to `127.0.0.1`. |
| `ZG_LOCAL_API_TOKEN` | random, per launch | Only your app can call the local inference routes. |
| `ZG_MODELS_DIR`, `ZG_DATA_DIR` | under `userData` | Survive app updates. Don't wipe them: a new identity makes the Mac a newcomer that gets less work at first. |
| `ZG_MAX_CONCURRENCY` | `1` | One inference at a time, gentle on a laptop. |
| `ZG_LOG_LEVEL` | `warn` | Use `info` while integrating. |
## Authentication
The worker authenticates with your **SDK key** (`zgpu-sdk-…`) through `ZG_OPERATOR_KEY`. The key only joins devices to your fleet, but it ships inside every copy of your app, so keep it out of source control and inject it at build time.
Never ship a ZeroGPU **API key** (`zgpu-api-…`) inside a desktop app. It authorizes paid inference for your whole organization, and anything in an app bundle can be extracted.
## Register device
Registration is automatic. On start, the worker runs a short CPU benchmark (about 5 seconds), creates a random device ID stored in `ZG_DATA_DIR`, registers the Mac with ZeroGPU, downloads and verifies its assigned model, loads it, and opens an outbound connection for tasks. Expect under 30 seconds on first launch and a few seconds afterwards.
All connections to ZeroGPU are outbound (HTTPS and WSS). The only listener is the local API on `127.0.0.1`.
## Start contributing compute
Create **one** `ZeroGpuWorker` in your main process and start it when the Mac is on power:
```js main.mjs theme={null}
import { app, powerMonitor } from "electron";
import { ZEROGPU_OPERATOR_KEY } from "./build-config.mjs"; // generated at build time, not committed
import { ZeroGpuWorker } from "./zerogpu-worker.mjs";
const worker = new ZeroGpuWorker({
operatorKey: ZEROGPU_OPERATOR_KEY,
logLevel: app.isPackaged ? "warn" : "info",
});
const startIfOnPower = () => {
if (!powerMonitor.isOnBatteryPower()) void worker.start();
};
app.whenReady().then(() => {
startIfOnPower();
powerMonitor.on("on-ac", startIfOnPower);
powerMonitor.on("resume", startIfOnPower);
powerMonitor.on("on-battery", () => void worker.stop());
powerMonitor.on("suspend", () => void worker.stop());
});
```
## Stop / pause
`worker.stop()` sends `SIGTERM`: the worker leaves the network, flushes telemetry, unloads its model, and exits within 5 seconds. To pause, call `stop()`; to resume, call `start()`. The power policy above does exactly this on battery and sleep.
Let the worker leave the network before your app quits:
```js main.mjs theme={null}
let workerStopped = false;
app.on("before-quit", (event) => {
if (workerStopped) return;
event.preventDefault();
worker.stop().finally(() => {
workerStopped = true;
app.quit();
});
});
```
## Device lifecycle
Check status from your main process with `await worker.status()`:
```json theme={null}
{
"running": true,
"status": "ready",
"ready": true,
"capacity": { "inFlight": 0, "queued": 0, "maxConcurrency": 1 },
"network": { "completedTasks": 3, "failedTasks": 0 }
}
```
`ready` turns `true` once a model is loaded and has passed a warm-up inference. `network.completedTasks` counts tasks ZeroGPU sent to this Mac. Use the `onExit` option to show status or restart after a delay; the worker protects itself against crash loops with a cooldown.
## Example integration
1. Start your app with `logLevel: "info"`.
2. Open the worker log at `~/Library/Logs//zerogpu-worker.log`. A healthy first start looks like this:
```text theme={null}
INFO [main] ZeroGPU Worker starting (env=production, fallback=reject)
INFO [register] Registering device 57d6219e-… with https://devices.zerogpu.ai/register (env=production)
INFO [register] Registered. 1 model recipe(s) assigned
INFO [models] Model zlm-v1-iab-classify-onnx@1 verified (4 files)
INFO [lifecycle] Device ready: iab_classify
```
3. Quit your app. The log ends with `[lifecycle] Shutdown (host_stop)`.
Switch `logLevel` back to `warn` for release builds.
### Packaging and signing
Native libraries must live outside the ASAR archive and be signed with your Developer ID. With electron-builder:
```json package.json theme={null}
{
"build": {
"asar": true,
"asarUnpack": [
"**/node_modules/onnxruntime-node/**/*",
"**/node_modules/sharp/**/*",
"**/node_modules/@img/**/*",
"**/node_modules/node-llama-cpp/**/*",
"**/node_modules/@node-llama-cpp/**/*"
],
"mac": {
"target": [{ "target": "dmg", "arch": ["arm64", "x64"] }],
"notarize": true
}
}
}
```
Build `arm64` and `x64` separately, each after `npm ci --os=darwin --cpu=`, so every architecture gets its matching native binaries.
### Other app shells
Not using Electron? Any app that can ship a Node.js 20+ runtime can run the same entry point as a child process with the same variables:
```bash theme={null}
ZG_OPERATOR_KEY="zgpu-sdk-…" \
ZG_LOCAL_API_PORT=52817 \
ZG_LOCAL_API_TOKEN="$(openssl rand -hex 24)" \
ZG_MODELS_DIR="$HOME/Library/Application Support/YourApp/zerogpu/models" \
ZG_DATA_DIR="$HOME/Library/Application Support/YourApp/zerogpu/data" \
node node_modules/@zerogpu/worker/dist/cli.js
```
Stop it with `SIGTERM`, allow 5 seconds for it to exit, and make sure it never outlives your app.
## Troubleshooting
| Symptom | Fix |
| - | - |
| Worker exits immediately with code `1`: `ZG_OPERATOR_KEY … is required` | The key didn't reach the worker's environment. Check the value you pass as `operatorKey`. |
| `Registration auth failure (401)`, then `policy says stop` | The key isn't valid for the target environment. Fix the key or `environment` and restart. |
| `Registration politely refused: ` | Normal: the network is declining this Mac for now. The worker retries by itself. |
| `status()` shows `ready: false` at first | Still booting. Allow up to \~30 seconds on first launch. |
| Packaged app: `dlopen` errors or `Could not load the "sharp" module` | Native files are still inside the ASAR archive, or the build is missing binaries for that architecture. See [Packaging and signing](#packaging-and-signing). |
| Packaged app: `Cannot find module '@zerogpu/worker/cli'` | Your bundler dropped the dependency. Keep `@zerogpu/worker` external and shipped in `node_modules`. |
| `network.completedTasks` stays at `0` | The Mac is connected, but the network hasn't needed it yet. Keep `ZG_DATA_DIR` persistent. |
| `npm install` fails with a `404` from another registry | Your `.npmrc` maps `@zerogpu` elsewhere. Use `npm install @zerogpu/worker --@zerogpu:registry=https://registry.npmjs.org`. |
# Telegram Mini Apps
Source: https://docs.zerogpu.ai/docs/edge-providers/sdk/telegram
Connect your Telegram Mini App to ZeroGPU and contribute device compute to the edge network with one script tag.
## Overview
Telegram Mini Apps run on the ZeroGPU browser SDK: one script tag in your Mini App's HTML turns the devices opening it into inference nodes on the ZeroGPU network. The SDK detects the Telegram WebApp environment automatically and adapts to it.
## Requirements
* A Telegram Mini App (a web app opened inside Telegram).
* An SDK key (`zgpu-sdk-…`) from the [Edge Operator Portal](https://edge.zerogpu.ai). When you add your app, select **Telegram Mini App** as an app type and use your `t.me` link as the website.
* The same browser requirements as the [Chrome / Web SDK](/docs/edge-providers/sdk/web#requirements): WebAssembly, IndexedDB, and Web Workers, all available in Telegram's in-app browser.
## Installation
Add the loader to your Mini App's HTML. It always resolves the latest released SDK:
```html theme={null}
```
## Initialization
The simplest setup is auto-init: put your SDK key on the script tag and the SDK starts when the page loads.
```html theme={null}
```
For manual init, use `ZeroGpuSdk.initZeroGpuSdk({ edgeOperatorKey })` exactly as in the [Chrome / Web SDK](/docs/edge-providers/sdk/web#initialization). All the same options apply.
## Authentication
The SDK authenticates with your **SDK key** (`zgpu-sdk-…`), passed as `edgeOperatorKey`. The key only joins devices to your fleet; it can't call the inference API or spend credits.
## Register device
Registration is automatic. Inside Telegram, the SDK:
* Detects `window.Telegram.WebApp` and registers the device with the `telegram-webapp` platform.
* Uses the Telegram user ID as `appUserId`, so you don't need to pass it.
* Downloads and caches its assigned model, then opens a connection for tasks.
## Start contributing compute
The device contributes compute while your Mini App is open. There's nothing else to call.
## Stop / pause
Keep the handle returned by `initZeroGpuSdk` and call `shutdown()` to stop:
```js theme={null}
const zerogpu = await ZeroGpuSdk.initZeroGpuSdk({ edgeOperatorKey: 'zgpu-sdk-your-key' });
// later, e.g. when the user turns resource sharing off
await zerogpu.shutdown();
```
There is no separate pause call. Closing the Mini App also stops contribution.
## Device lifecycle
The lifecycle matches the [Chrome / Web SDK](/docs/edge-providers/sdk/web#device-lifecycle): `starting`, `running`, `degraded`, `shutdown`, or `error`, with `degraded`, `recovered`, and `shutdown` events.
Telegram's in-app WebViews behave differently from regular browsers, so the SDK adapts its memory and storage checks there, and includes a guard that stops it from restarting repeatedly if the WebView keeps crashing and reloading.
## Example integration
```html index.html theme={null}
```
To verify, open the Mini App in Telegram Desktop or Telegram Web with developer tools, and watch the console as the SDK registers the device, loads a model, and becomes ready. Turn `enableConsoleLogs` off for release.
## Troubleshooting
| Symptom | Fix |
| - | - |
| Rejected at registration / `401` | The SDK key is wrong or inactive. Check it in the Edge Operator Portal. |
| SDK pinned to an old version | Load `dist/loader.js`, not `zerogpu-browser-sdk.umd.js` directly. |
| No SDK activity in the console | Add `enableConsoleLogs="true"` to the script tag. |
| `Init skipped: crash-loop guard active` | The WebView crashed repeatedly while loading the model, so the SDK is in a cooldown. It starts again once the cooldown ends. |
See [Chrome / Web troubleshooting](/docs/edge-providers/sdk/web#troubleshooting) for worker and CSP issues.
# Chrome / Web
Source: https://docs.zerogpu.ai/docs/edge-providers/sdk/web
Contribute compute from websites and Chrome extensions with the ZeroGPU browser SDK.
## Overview
The ZeroGPU browser SDK turns the browsers running your website or Chrome extension into on-device inference nodes on the ZeroGPU network. It downloads a small model, registers the device, and serves inference tasks locally, in a Web Worker so your page's main thread stays responsive.
There are two ways to integrate:
| You're building | Use |
| - | - |
| **A website or web app** | The always-latest loader script from `js-sdk.zerogpu.ai`, or the npm package |
| **A Chrome extension (Manifest V3)** | The npm package, vendored into your extension with the `zerogpu` CLI. MV3 doesn't allow remotely hosted code. |
Building a Telegram Mini App? See [Telegram Mini Apps](/docs/edge-providers/sdk/telegram).
## Requirements
* A modern desktop or mobile browser with WebAssembly, IndexedDB (for the model cache), and Web Workers.
* An SDK key (`zgpu-sdk-…`) from the [Edge Operator Portal](https://edge.zerogpu.ai).
* **Websites with a strict Content Security Policy:** allow `blob:` workers, or host the worker yourself and set `overrides.inference.workerUrl`.
* **Chrome extensions:** Manifest V3, plus Node.js and npm at build time only. Nothing from `node_modules` ships in your extension.
## Installation
Add the loader to your page. It always resolves the latest released SDK, so you never pin or bump versions:
```html theme={null}
```
Or install from npm if you bundle your own JavaScript:
```bash theme={null}
npm install @zerogpu/browser-extension-sdk
```
```bash theme={null}
npm install @zerogpu/browser-extension-sdk
npx zerogpu init
```
`npx zerogpu init` copies the SDK runtime into `vendor/zerogpu/`, creates `offscreen.html`, `offscreen.js`, and `background.js` (it never overwrites your files), and adds what the SDK needs to `manifest.json`: the `offscreen` and `storage` permissions, a CSP entry allowing `'wasm-unsafe-eval'`, host permissions for model downloads, and an `externally_connectable` entry for the ZeroGPU settings page.
Using your own service worker? Merge the generated `background.js` snippet into it, and add `"prebuild": "zerogpu vendor"` to your build scripts.
## Initialization
**Script tag (auto-init).** The SDK starts as soon as `edgeOperatorKey` is present:
```html theme={null}
```
**Manual init.** Load the loader without a key and call `initZeroGpuSdk`. Calls made before the SDK finishes loading are queued and replayed:
```html theme={null}
```
**ESM:**
```ts theme={null}
import { initZeroGpuSdk } from '@zerogpu/browser-extension-sdk';
const zerogpu = await initZeroGpuSdk({
edgeOperatorKey: 'zgpu-sdk-your-key',
});
```
| Option | Description |
| - | - |
| `edgeOperatorKey` | Your SDK key. Required. |
| `appUserId` | Optional stable user identifier for your own reporting. |
| `customParams` | Up to three reporting slots, `cust_param1`–`cust_param3`. Values only; no personal data. Script tag: `data-cust-param1`…`3`. |
| `overrides.telemetry.enableConsoleLogs` | Log SDK activity to the console (redacted). Script tag: `enableConsoleLogs="true"`. |
| `overrides.inference.workerUrl` | Same-origin worker URL for pages whose CSP forbids `blob:` workers. |
Open the generated `offscreen.js` and add your SDK key:
```js offscreen.js theme={null}
import { initZeroGpuOffscreen } from "./vendor/zerogpu/zerogpu-offscreen.js";
initZeroGpuOffscreen({
edgeOperatorKey: "zgpu-sdk-your-key",
enableConsoleLogs: true
});
```
| Option | Required | Description |
| - | - | - |
| `edgeOperatorKey` | yes | Your SDK key. |
| `enableConsoleLogs` | no | Log SDK activity to the offscreen console. |
| `inferenceWorker` | no | Run inference in the SDK's worker. Default `true`. |
| `appUserId` | no | A stable identifier for the current user. |
| `customParams` | no | `{ cust_param1, cust_param2, cust_param3 }` reporting slots. |
## Authentication
The SDK authenticates with your **SDK key** (`zgpu-sdk-…`), passed as `edgeOperatorKey`. The key can only join devices to your fleet; it can't call the inference API or spend credits. Still, inject it at build time rather than committing it.
## Register device
Registration is automatic. On start, the SDK collects coarse device capabilities (platform, CPU cores, approximate memory, battery level, connection type), downloads and caches its assigned model in IndexedDB, registers with the ZeroGPU device registry, and opens a WebSocket for tasks.
## Start contributing compute
* **Websites:** the SDK starts when it's initialized with your SDK key and keeps contributing while the page is open.
* **Chrome extensions:** the SDK runs in a background offscreen document and starts automatically whenever your extension loads.
## Stop / pause
`initZeroGpuSdk` returns a handle. Call `shutdown()` to stop gracefully:
```ts theme={null}
await zerogpu.shutdown();
```
Shutdown lasts until the page initializes the SDK again; there is no separate pause call.
Users must be able to turn resource sharing off. New installs are opted in; while a user is opted out, the offscreen document is never created, so nothing starts or connects. The choice persists across restarts.
Add the opt-out link to an extension page you already show, such as your popup:
```html theme={null}
Resource sharing
```
Or control it from your service worker:
```js theme={null}
await ZeroGpuBackground.getZeroGpuConsent();
await ZeroGpuBackground.setZeroGpuConsent(false); // stops the SDK, stays off
```
If your consent flow requires an explicit yes first, write `false` on install and flip it when the user agrees.
## Device lifecycle
On websites, the handle's `status` is one of `starting`, `running`, `degraded`, `shutdown`, or `error`. Subscribe to changes:
```ts theme={null}
zerogpu.on('degraded', ({ code, message }) => { /* resource pressure */ });
zerogpu.on('recovered', () => { /* back to normal */ });
zerogpu.on('shutdown', ({ code }) => { /* the SDK stopped */ });
```
`initZeroGpuSdk` never throws: if the SDK can't run on a device, `status` reports it instead of breaking your page. Before downloading models, the SDK checks memory and storage, and blocks downloads when the battery is below 20% and the device isn't charging.
## Example integration
```html index.html theme={null}
```
Open the page and check the console: with `enableConsoleLogs` on, you'll see the SDK register the device, load a model, and become ready.
1. Go to `chrome://extensions`, turn on **Developer mode**, and click **Load unpacked**.
2. On your extension's card, open **Inspect views: offscreen.html**.
3. With `enableConsoleLogs: true`, watch the SDK start, register the device, load a model, and become ready.
Check your setup at any time:
```bash theme={null}
npx zerogpu doctor
```
After each SDK update, run `npx zerogpu vendor` (or wire it into `prebuild`) and republish your extension.
## Troubleshooting
| Symptom | Fix |
| - | - |
| Rejected at registration / `401` | The SDK key is wrong or inactive. Check it in the Edge Operator Portal. |
| `Inference worker unavailable; models run on the main thread` | Websites: your CSP blocks `blob:` workers; set `overrides.inference.workerUrl`. Extensions: the vendored worker is missing or stale; run `npx zerogpu vendor`. |
| Extension: CSP error mentioning `'wasm-unsafe-eval'` | Your manifest's CSP must allow `'wasm-unsafe-eval'`. Re-run `npx zerogpu init` or `npx zerogpu doctor`. |
| Extension: import fails / runtime files missing | Run `npx zerogpu vendor` and confirm `vendor/zerogpu/` exists. |
| Extension: model download blocked | Allow the model host in your manifest's host permissions; `npx zerogpu doctor` flags this. |
| Extension: out of date after an update | `npx zerogpu doctor` reports drift; run `npx zerogpu vendor`. |
| Website pinned to an old SDK | You're loading `zerogpu-browser-sdk.umd.js` directly. Use `dist/loader.js` instead. |
# Embeddings
Source: https://docs.zerogpu.ai/docs/embeddings
384-dimensional text embeddings for semantic search, RAG, clustering, and deduplication.
Embedding models turn text into a vector so that distance between vectors tracks closeness in meaning. That is what powers semantic search, retrieval-augmented generation, deduplication, clustering, and recommendation. Call the dedicated [Embeddings API](/api-reference/embeddings) (`POST /v1/embeddings`). An embedding model is routable only on this endpoint and returns OpenAI's native embeddings envelope, so an existing client only needs its base URL and model id changed.
| Model | Input /1M | Output /1M | Max tokens |
| - | -: | -: | -: |
|
all-minilm-l6-v2 | \$0.004 | Not billed | 512 |
|
bge-small-en-v1.5 | \$0.004 | Not billed | 512 |
Both models return **384-dimensional** vectors, so they are interchangeable in an existing index. Embeddings are billed on input tokens only.
## all-minilm-l6-v2
> Sentence-Transformers' all-MiniLM-L6-v2 is the default workhorse of semantic search. It maps a sentence or short paragraph to a 384-dimensional vector, trained with contrastive learning on more than a billion sentence pairs, so cosine distance between two vectors tracks how close the two texts are in meaning. At 22.7M parameters it embeds fast and cheap enough to index a whole corpus and re-embed it whenever your content changes. Inputs are truncated at 256 tokens, so embed chunks rather than whole documents.
**References:** [Model card](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Embeddings API theme={null}
curl https://api.zerogpu.ai/v1/embeddings \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "all-minilm-l6-v2",
"input": "ZeroGPU runs high-volume inference tasks on small models at the edge."
}'
```
```json Response theme={null}
{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [0.012601, -0.072932, 0.043332, 0.028129, 0.033064, -0.078302, -0.153619, -0.011621]
}
],
"model": "all-MiniLM-L6-v2",
"usage": { "prompt_tokens": 18, "total_tokens": 18 }
}
```
The vector above is truncated for readability; a real response carries all 384 values. The `model` field reads `all-MiniLM-L6-v2`, the upstream capitalization of the id you send.
## bge-small-en-v1.5
> BAAI's BGE-small-en-v1.5 is a retrieval-first English embedding model and one of the strongest performers on the MTEB benchmark for its size. It produces the same 384-dimensional vectors as all-minilm-l6-v2, so it is a drop-in swap in an existing index, but it takes a 512-token window instead of 256 and is tuned specifically for dense retrieval rather than general sentence similarity. At 33M parameters it is the one to reach for when the job is ranking passages against a query.
**References:** [Model card](https://huggingface.co/BAAI/bge-small-en-v1.5) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
Embed a batch by passing an array. Each `data[i].index` maps a vector back to its input.
```bash Batch embeddings theme={null}
curl https://api.zerogpu.ai/v1/embeddings \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"model": "bge-small-en-v1.5",
"input": ["first text", "second text"]
}'
```
## Which one to pick
Start with `all-minilm-l6-v2` for general semantic similarity over short chunks. Move to `bge-small-en-v1.5` when the job is English retrieval, when your chunks run past 256 tokens, or when retrieval quality is the bottleneck. Both cost the same and return the same vector width, so switching is a one-line change plus a reindex.
# How ZeroGPU works
Source: https://docs.zerogpu.ai/docs/how-zerogpu-works
ZeroGPU turns idle compute into one programmable inference layer - specialized small models, an edge-powered network, and routing handled for you.
ZeroGPU turns idle compute into one programmable inference layer. You send a request; we run it on a specialized small or nano model, on the cheapest compute that can serve it well.
## Specialized small and nano models
ZeroGPU runs purpose-built ZLMs (ZeroGPU Language Models) for high-volume tasks like IAB classification and signal extraction, alongside a catalog of open small and nano models - DeBERTa, GLiNER, LFM2.5, Llama 3.1 8B. Small enough to run at the edge, good enough for production. See the [Model Catalog](/docs/model-catalog).
## An edge-powered network
Requests run across a hybrid of:
Phones, gaming PCs.
Mid-sized models, higher load.
Consistent performance and burst capacity.
## Routing
For each request, ZeroGPU picks the right model and the right compute by capability, availability, and load - and routes geographically to cut latency. You call one endpoint; the orchestration is handled for you.
This is network-side routing (which model, which compute). It's distinct from the ZeroGPU Router in the skills/plugins, which decides - on the client side - which steps of an agent run to offload to ZeroGPU at all. See [Integrations → Claude Code Plugin](/integrations/claude-code-plugin).
# Model Catalog
Source: https://docs.zerogpu.ai/docs/model-catalog
Browse ZeroGPU models, compare pricing, and pick the model ID to call.
The **Model Catalog** lets you browse every available ZeroGPU model and compare **pricing** across the tasks you care about. It's useful when you're selecting which `model` identifier to send to `POST /v1/responses`.
Sections on this page: [At a glance](#at-a-glance) (pricing table), [Detailed model cards](#detailed-model-cards), and [Model library by task](#model-library-by-task).
## At a glance
| Model | Input /1M | Output /1M | Cached input /1M | Task | Max tokens |
| - | -: | -: | -: | - | -: |
|
deepseek-v4.1-flash | \$0.30 | \$1.20 | \$0.003 | Text Generation | 1,048,576 |
|
glm-5.3-flash | \$0.10 | \$0.35 | \$0.015 | Text Generation | 1,048,576 |
|
gpt-5.4-nano | \$0.20 | \$1.25 | \$0.02 | Text Generation | 400,000 |
|
gpt-5.6-luna | \$0.20 | \$1.20 | \$0.20 | Text Generation | 272,000 |
|
gpt-4.1-mini | \$0.40 | \$1.60 | \$0.10 | Text Generation | 1,047,576 |
|
gpt-oss-120b | \$0.15 | \$0.60 | \$0.03 | Text Generation | 131,072 |
|
qwen3-30b-a3b-fp8 | \$0.10 | \$0.45 | \$0.05 | Text Generation | 32,768 |
|
llama-3.1-8b-instruct-fast | \$0.15 | \$0.28 | \$0.025 | Text Generation | 131,072 |
|
llama-guard-4-12b | \$0.18 | \$0.18 | — | Text Generation | 163,840 |
|
zlm-v2-iab-classify-edge-enriched | \$0.05 | \$0.15 | — | Text Classification | 800 |
|
zlm-v1-iab-classify-edge | \$0.02 | \$0.05 | — | Text Classification | 400 |
|
zlm-v1-iab-domain-classifier | \$0.02 | \$0.05 | — | Text Classification | 100 |
|
zlm-v1-moderation-edge | \$0.10 | \$0.15 | — | Text Moderation | 800 |
|
gliner2.5-base-v1 | \$0.02 | \$0.05 | — | Text Classification | — |
|
gliner2.5-multi-v1 | \$0.02 | \$0.05 | — | Text Classification | — |
|
deberta-v3-small | \$0.02 | \$0.05 | — | Text Classification | 400 |
|
LFM2.5-1.2B-Thinking | \$0.02 | \$0.05 | — | Text Generation | 32,768 |
|
LFM2.5-1.2B-Instruct | \$0.02 | \$0.05 | — | Text Generation | 32,768 |
|
qwen3.6-35b-a3b | \$0.20 | \$1.50 | \$0.20 | Text Generation | — |
|
zlm-v1-signal-extract | \$0.04 | \$0.10 | — | Text Classification | 400 |
|
gliner2.5-decide-v1 | \$0.004 | Not billed | — | Text Classification | — |
|
all-minilm-l6-v2 | \$0.004 | Not billed | — | Text Embedding | 512 |
|
bge-small-en-v1.5 | \$0.004 | Not billed | — | Text Embedding | 512 |
[Audio models](/docs/audio) are called on `POST /v1/audio/transcriptions` and `POST /v1/audio/speech` rather than `/v1/responses`, and are billed per minute of audio instead of per token, rounded up to the next whole minute with a one-minute minimum.
| Model | Price /min | Task | Limits |
| - | -: | - | - |
|
whisper-tiny | \$0.02 | Speech-to-Text | 25 MB, 10 minutes of audio |
|
chatterbox-nano | \$0.01 | Text-to-Speech | 2,000 characters |
## Detailed model cards
deepseek-v4.1-flash
1,048,576 context window\$0.30 / 1M input\$1.20 / 1M output\$0.003 / 1M cached input
DeepSeek's DeepSeek-V4.1-Flash is an open-weight sparse Mixture-of-Experts model and the first built on DeepSeek's Causal Encoder-Decoder (CED) architecture, activating 8B parameters on input and 16B on output. It…
glm-5.3-flash
1,048,576 context window\$0.10 / 1M input\$0.35 / 1M output\$0.015 / 1M cached input
Z.ai's GLM-5.3-Flash is an efficient open-weight model for coding and long-horizon agent tasks, served on ZeroGPU for general text generation. Its hybrid sparse and linear attention keeps…
gpt-5.4-nano
400,000 context window\$0.20 / 1M input\$1.25 / 1M output\$0.02 / 1M cached input
OpenAI's GPT-5.4 nano is the most cost-efficient model in the GPT-5.4 family, served on ZeroGPU for high-volume and latency-sensitive workloads such as classification, extraction, routing, and…
gpt-5.6-luna
272,000 context window\$0.20 / 1M input\$1.20 / 1M output\$0.20 / 1M cached input
OpenAI's GPT-5.6 Luna is the cost-optimized model of the GPT-5.6 family, served on ZeroGPU for cost-sensitive, high-volume workloads. It supports adjustable reasoning effort, function calling, and…
gpt-4.1-mini
1,047,576 context window\$0.40 / 1M input\$1.60 / 1M output\$0.10 / 1M cached input
OpenAI's GPT-4.1 mini is the fast, cost-efficient model of the GPT-4.1 family, served on ZeroGPU for general text generation. It excels at instruction following and tool calling, supports function…
gpt-oss-120b
131,072 context window\$0.15 / 1M input\$0.60 / 1M output\$0.03 / 1M cached input
OpenAI's gpt-oss-120b is an open-weight Mixture-of-Experts model with 117B total parameters (5.1B active per token), served on ZeroGPU for general text generation. It reasons through a problem…
qwen3-30b-a3b-fp8
32,768 context window\$0.10 / 1M input\$0.45 / 1M output\$0.05 / 1M cached input
Alibaba's Qwen3-30B-A3B is an open-weight Mixture-of-Experts model with 30.5B total parameters (3.3B active per token), served on ZeroGPU as an FP8 build for efficient inference. It thinks through a problem…
llama-3.1-8b-instruct-fast
131,072 max tokens\$0.15 / 1M input\$0.28 / 1M output\$0.025 / 1M cached input
Meta's Llama 3.1 Instruct, tuned for fast, low-cost summarization at scale on the ZeroGPU edge network. Its 128K-token context window takes in entire documents, long transcripts, and full email or…
llama-guard-4-12b
Text GenerationSafety classificationText ModerationBrand Safety12B params163,840 context window\$0.18 / 1M input\$0.18 / 1M output
Meta's Llama Guard 4 12B is a multimodal safety classification model for moderating text, images, and mixed text-image inputs. It evaluates both incoming prompts…
zlm-v2-iab-classify-edge-enriched
800 max tokens\$0.05 / 1M input\$0.15 / 1M output
The enriched variant of ZeroGPU's IAB classifier turns a single inference call into a full content-intelligence profile not just a label, but everything a contextual pipeline needs to act on. Each…
zlm-v1-iab-classify-edge
400 max tokens\$0.02 / 1M input\$0.05 / 1M output
ZeroGPU's IAB classifier maps any text to the industry-standard IAB Content Taxonomy in a single, fast inference call. Each call returns categories across both the 1.0 and 2.2 taxonomies plus matched…
zlm-v1-iab-domain-classifier
100 max tokens\$0.02 / 1M input\$0.05 / 1M output
ZeroGPU's Domain IAB Classifier maps a raw domain name straight to the IAB Content Taxonomy, returning content categories, topics, keywords, and user-intent signals. It needs only the domain as input, cutting payload size by up to 10x versus page-level…
zlm-v1-moderation-edge
800 max tokens\$0.10 / 1M input\$0.15 / 1M output
ZeroGPU's moderation model returns the complete OpenAI 13-category taxonomy — a flagged verdict, category booleans, and calibrated scores — as a drop-in for omni-moderation-latest. In head-to-head benchmarks it wins the binary safe/unsafe decision (0.899 vs 0.853 F1) and 9 of 13 harm categories, and returns verdicts 1.2–1.8× faster on production-range…
gliner2.5-base-v1
194M params\$0.02 / 1M input\$0.05 / 1M output
Fastino's GLiNER2.5 Base is an English schema-based information extraction model built on DeBERTa-v3-base. A single model covers entity extraction, text classification, structured record extraction…
gliner2.5-multi-v1
287M params\$0.02 / 1M input\$0.05 / 1M output
Fastino's GLiNER2.5 Multi is a multilingual information extraction model built on mDeBERTa-v3-base. It supports zero-shot named entity recognition, text classification, and structured JSON extraction…
deberta-v3-small
400 max tokens\$0.02 / 1M input\$0.05 / 1M output
Microsoft's DeBERTa-v3-small is a fast, lightweight zero-shot text classifier for high-volume routing, filtering, and tagging. Hand it any text alongside your own candidate labels and it returns a…
LFM2.5-1.2B-Thinking
32,768 max tokens\$0.02 / 1M input\$0.05 / 1M output
Liquid AI's LFM2.5-1.2B-Thinking is a compact reasoning model that works through a problem step by step before it answers. Built by Liquid AI, it generates an explicit chain-of-thought trace so for…
LFM2.5-1.2B-Instruct
32,768 max tokens\$0.02 / 1M input\$0.05 / 1M output
Liquid AI's LFM2.5-1.2B-Instruct is a hybrid architecture model purpose-built for on-device deployment, trained on 28 trillion tokens with multi-stage reinforcement learning. It delivers…
qwen3.6-35b-a3b
35B params\$0.20 / 1M input\$1.50 / 1M output\$0.20 / 1M cached input
Alibaba's Qwen3.6-35B-A3B is a fast, open-weight multimodal model for applications that need to understand text, images, and video, served on ZeroGPU as an FP8 build. It suits visual question answering, document and screenshot analysis…
zlm-v1-signal-extract
Text ClassificationSignal extractionAd TechChat80M params400 context window\$0.04 / 1M input\$0.10 / 1M output
ZeroGPU's signal extractor turns unstructured text into structured signals that downstream systems can act on. One inference call returns topics, keywords, intent…
gliner2.5-decide-v1
486M params\$0.004 / 1M input
Fastino's GLiNER2.5 Decide is a 486M-parameter zero-shot decision and classification model built for operational AI workflows. You supply the labels or decision options at request time to classify intent, route agents and tools, triage support requests, make moderation decisions…
all-minilm-l6-v2
512 max tokens\$0.004 / 1M input
Sentence-Transformers' all-MiniLM-L6-v2 is the default workhorse of semantic search. It maps a sentence or short paragraph to a 384-dimensional vector, trained with contrastive learning on more than a billion sentence pairs…
bge-small-en-v1.5
512 max tokens\$0.004 / 1M input
BAAI's BGE-small-en-v1.5 is a retrieval-first English embedding model and one of the strongest performers on the MTEB benchmark for its size. It produces the same 384-dimensional vectors, with a 512-token window…
whisper-tiny
Speech-to-Text39M params\$0.02 / minute
OpenAI's Whisper Tiny is the smallest model in the Whisper family of speech recognition models, at 39M parameters. It is the multilingual checkpoint: it transcribes speech in the language it was spoken…
chatterbox-nano
Text-to-SpeechVoice cloning110M params\$0.01 / minute
Resemble AI's Chatterbox Nano is a 110M-parameter English text-to-speech model built for fast, low-cost speech generation. It speaks your text in a built-in voice, or clones a speaker…
## Model library by task
7 models: `deepseek-v4.1-flash`, `glm-5.3-flash`, `qwen3-30b-a3b-fp8`, `qwen3.6-35b-a3b`, `gpt-oss-120b`, `llama-3.1-8b-instruct-fast`, `llama-guard-4-12b`
12 models: `deepseek-v4.1-flash`, `glm-5.3-flash`, `gpt-5.4-nano`, `gpt-5.6-luna`, `gpt-4.1-mini`, `gpt-oss-120b`, `qwen3-30b-a3b-fp8`, `qwen3.6-35b-a3b`, `llama-3.1-8b-instruct-fast`, `llama-guard-4-12b`, `LFM2.5-1.2B-Thinking`, `LFM2.5-1.2B-Instruct`
2 models: `whisper-tiny`, `chatterbox-nano`
8 models: `zlm-v2-iab-classify-edge-enriched`, `zlm-v1-iab-classify-edge`, `zlm-v1-iab-domain-classifier`, `deberta-v3-small`, `zlm-v1-signal-extract`, `gliner2.5-base-v1`, `gliner2.5-multi-v1`, `gliner2.5-decide-v1`
1 model: `zlm-v1-moderation-edge`
2 models: `all-minilm-l6-v2`, `bge-small-en-v1.5`
4 models: `zlm-v1-iab-classify-edge`, `zlm-v2-iab-classify-edge-enriched`, `zlm-v1-iab-domain-classifier`, `zlm-v1-signal-extract`
# Moderation
Source: https://docs.zerogpu.ai/docs/moderation
OpenAI-compatible content moderation, benchmarked against omni-moderation-latest.
Moderation models screen text for unsafe, harmful, or policy-sensitive content before it reaches your application or model workflow. Call the dedicated [Moderations API](/api-reference/moderations) (`POST /v1/moderations`) — a moderation model is routable only on this endpoint and returns OpenAI's native moderations envelope, so it drops into any pipeline written against `omni-moderation-latest`.
| Model | Input /1M | Output /1M | Max tokens |
| - | -: | -: | -: |
|
zlm-v1-moderation-edge | \$0.10 | \$0.15 | 800 |
## zlm-v1-moderation-edge
> ZeroGPU's moderation model screens text for unsafe, harmful, or policy-sensitive content and returns the complete OpenAI 13-category taxonomy (a `flagged` verdict, per-category booleans, and calibrated `category_scores`), so it drops into any pipeline written against `omni-moderation-latest`. Under the hood it's an 86M-parameter DeBERTa encoder with a shared trunk feeding one binary safe/unsafe head and 13 category heads, with per-category thresholds calibrated on held-out validation data. In [head-to-head benchmarks](https://zerogpu.ai/benchmarks/moderation-edge) against OpenAI omni-moderation it wins the binary safe/unsafe decision (0.899 vs 0.853 F1) and 9 of 13 harm categories, with the largest gains on graphic violence, illicit content, and self-harm, while returning verdicts 1.2–1.8× faster at the median on production-range inputs, because inference is co-located at the edge instead of a round trip to a central API. Moderation sits inline in front of every response your app serves; this is the model that's fast and accurate enough to live there.
**References:** [Moderation benchmark](https://zerogpu.ai/benchmarks/moderation-edge) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
Send the text to classify as `input` — a string, an array of strings (one verdict per element), or an array of `{ "type": "text", "text": "…" }` content parts.
```bash Moderations API theme={null}
curl https://api.zerogpu.ai/v1/moderations \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-moderation-edge",
"input": "I am so angry at this person that I want to hurt them. They are worthless and should be scared of what I might do next."
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-moderation-edge",
"messages": [
{
"role": "user",
"content": "I am so angry at this person that I want to hurt them. They are worthless and should be scared of what I might do next."
}
]
}'
```
On `/v1/moderations` the response is OpenAI's native moderations envelope — an `id`, the resolved `model`, and a `results` array (one entry per input). Each result carries a `flagged` verdict, per-category `categories` booleans, `category_scores` in `[0, 1]`, and `category_applied_input_types` (always `["text"]` for this text-only model), with all 13 categories present in OpenAI's order:
```json Response theme={null}
{
"id": "modr-0a1b2c3d4e5f60718293a4b5c6d7e8f90",
"model": "zlm-v1-moderation-edge",
"results": [
{
"flagged": true,
"categories": {
"harassment": true,
"harassment/threatening": true,
"hate": false,
"hate/threatening": false,
"illicit": true,
"illicit/violent": true,
"self-harm": false,
"self-harm/intent": false,
"self-harm/instructions": false,
"sexual": false,
"sexual/minors": false,
"violence": true,
"violence/graphic": false
},
"category_scores": {
"harassment": 0.82545,
"harassment/threatening": 0.957703,
"hate": 0.21574,
"hate/threatening": 0.168273,
"illicit": 0.732167,
"illicit/violent": 0.780693,
"self-harm": 0.015232,
"self-harm/intent": 0.017179,
"self-harm/instructions": 0.01807,
"sexual": 0.035671,
"sexual/minors": 0.094207,
"violence": 0.665897,
"violence/graphic": 0.198346
},
"category_applied_input_types": {
"harassment": ["text"],
"harassment/threatening": ["text"],
"hate": ["text"],
"hate/threatening": ["text"],
"illicit": ["text"],
"illicit/violent": ["text"],
"self-harm": ["text"],
"self-harm/intent": ["text"],
"self-harm/instructions": ["text"],
"sexual": ["text"],
"sexual/minors": ["text"],
"violence": ["text"],
"violence/graphic": ["text"]
}
}
]
}
```
# Open Weight
Source: https://docs.zerogpu.ai/docs/open-weight
The open-weight frontier-class models served on ZeroGPU, with pricing and context windows.
Open-weight models ship with published weights and permissive licenses, so you can inspect them, self-host them, and avoid lock-in to a closed vendor. ZeroGPU serves seven of them — for reasoning, coding, agentic workflows, multimodal understanding, high-volume summarization, and safety classification — through the same OpenAI-compatible API as every other model in the [catalog](/docs/model-catalog).
Full request and response examples live on the [Text Generation](/docs/text-generation) page. Open-weight speech-to-text and text-to-speech models are on [Audio Models](/docs/audio).
## At a glance
| Model | Input /1M | Output /1M | Cached input /1M | Max tokens |
| - | -: | -: | -: | -: |
|
deepseek-v4.1-flash | \$0.30 | \$1.20 | \$0.003 | 1,048,576 |
|
glm-5.3-flash | \$0.10 | \$0.35 | \$0.015 | 1,048,576 |
|
qwen3-30b-a3b-fp8 | \$0.10 | \$0.45 | \$0.05 | 32,768 |
|
qwen3.6-35b-a3b | \$0.20 | \$1.50 | \$0.20 | — |
|
gpt-oss-120b | \$0.15 | \$0.60 | \$0.03 | 131,072 |
|
llama-3.1-8b-instruct-fast | \$0.15 | \$0.28 | \$0.025 | 131,072 |
|
llama-guard-4-12b | \$0.18 | \$0.18 | — | 163,840 |
## Model cards
deepseek-v4.1-flash
1,048,576 context window\$0.30 / 1M input\$1.20 / 1M output\$0.003 / 1M cached input
DeepSeek's DeepSeek-V4.1-Flash is an open-weight sparse Mixture-of-Experts model and the first built on DeepSeek's Causal Encoder-Decoder (CED) architecture, activating 8B parameters on input and 16B on output. It…
glm-5.3-flash
1,048,576 context window\$0.10 / 1M input\$0.35 / 1M output\$0.015 / 1M cached input
Z.ai's GLM-5.3-Flash is an efficient open-weight model for coding and long-horizon agent tasks, served on ZeroGPU for general text generation. Its hybrid sparse and linear attention keeps…
qwen3-30b-a3b-fp8
32,768 context window\$0.10 / 1M input\$0.45 / 1M output\$0.05 / 1M cached input
Alibaba's Qwen3-30B-A3B is an open-weight Mixture-of-Experts model with 30.5B total parameters (3.3B active per token), served on ZeroGPU as an FP8 build for efficient inference. It thinks through a problem…
qwen3.6-35b-a3b
35B params\$0.20 / 1M input\$1.50 / 1M output\$0.20 / 1M cached input
Alibaba's Qwen3.6-35B-A3B is a fast, open-weight multimodal model for applications that need to understand text, images, and video, served on ZeroGPU as an FP8 build. It suits visual question answering, document and screenshot analysis…
gpt-oss-120b
131,072 context window\$0.15 / 1M input\$0.60 / 1M output\$0.03 / 1M cached input
OpenAI's gpt-oss-120b is an open-weight Mixture-of-Experts model with 117B total parameters (5.1B active per token), served on ZeroGPU for general text generation. It reasons through a problem…
llama-3.1-8b-instruct-fast
131,072 max tokens\$0.15 / 1M input\$0.28 / 1M output\$0.025 / 1M cached input
Meta's Llama 3.1 Instruct, tuned for fast, low-cost summarization at scale on the ZeroGPU edge network. Its 128K-token context window takes in entire documents, long transcripts, and full email or…
llama-guard-4-12b
Text GenerationSafety classificationText ModerationBrand Safety12B params163,840 context window\$0.18 / 1M input\$0.18 / 1M output
Meta's Llama Guard 4 12B is a multimodal safety classification model for moderating text, images, and mixed text-image inputs. It evaluates both incoming prompts…
# Production patterns
Source: https://docs.zerogpu.ai/docs/production-patterns
What to get right when you move ZeroGPU from a first call into production.
Keep API keys in environment variables, never in source or client-side code. Handle the common status codes explicitly: 401 (bad API key), 403 (bad project ID), and 429 (rate limit). Set sensible timeouts and retries with backoff on 429 and 5xx. For large, non-real-time jobs, use the Batch and Files API instead of the synchronous endpoint - streaming is not supported in batch mode. Already on the OpenAI SDK? The drop-in client shown in the [Introduction](/) is the recommended way to call ZeroGPU from application code.
## Keep secrets out of source
Read your `x-api-key` and `x-project-id` from the environment (or a secrets manager) and inject them at deploy time. Never commit them, never ship them in a browser bundle or mobile app - a key embedded in client-side code is a public key.
ZeroGPU calls authenticate from your backend. If you need to call from a browser or mobile client, proxy the request through a server you control so the key stays server-side.
```bash theme={null}
# .env (git-ignored) - load with your process manager or dotenv
export ZEROGPU_API_KEY="zgpu-..."
export ZEROGPU_PROJECT_ID="..."
```
## Handle status codes explicitly
Branch on the status code. Authentication and authorization errors are permanent - retrying them just burns time and quota. Rate limits and server errors are transient - those are the ones to retry.
| Status | Meaning | What to do |
| - | - | - |
| `200` | Success | Parse and use the response. |
| `400` | Bad request | Fix the request body. Do **not** retry. |
| `401` | Bad API key | Check `x-api-key`. Do **not** retry. |
| `403` | Bad project ID | Check `x-project-id` and permissions. Do **not** retry. |
| `420` | Input over token limit | Shorten the input. Do **not** retry unchanged. |
| `429` | Rate limit reached | Wait at least `Retry-After` seconds, then retry. See [Rate limits](#rate-limits). |
| `5xx` | Server error | Retry with exponential backoff. |
Treat `408` (request timeout) and `409` (conflict) the same as `5xx` for retry purposes. Network errors and client-side timeouts are retriable too.
## Rate limits
Your organization has limits for each model, shared by all of its API keys:
* **Requests per minute**
* **Tokens per minute** - counted when a request is accepted: the estimated input tokens plus `max_tokens` (`max_completion_tokens`, or `max_output_tokens` on the Responses API) for each of `n` choices. Tokens a response doesn't use are not given back, so set `max_tokens` close to the size of the response you expect.
* **Concurrent requests** - requests still in progress, including open streams.
Counts reset at the start of each minute. Audio endpoints have request and concurrency limits, but no token limit.
Responses carry your limits in headers. A header is left out when that limit doesn't apply.
| Header | Example | Meaning |
| - | - | - |
| `x-ratelimit-limit-requests` | `300` | Requests allowed per minute |
| `x-ratelimit-remaining-requests` | `295` | Requests left this minute |
| `x-ratelimit-reset-requests` | `37s` | Time until the request count resets |
| `x-ratelimit-limit-tokens` | `500000` | Tokens allowed per minute |
| `x-ratelimit-remaining-tokens` | `499000` | Tokens left this minute |
| `x-ratelimit-reset-tokens` | `37s` | Time until the token count resets |
| `x-ratelimit-limit-concurrent-requests` | `16` | Requests allowed in progress at once |
| `x-ratelimit-remaining-concurrent-requests` | `15` | Requests you can start right now |
A request over a limit is rejected with `429` before it runs, and `error.code` says which limit it hit:
```json theme={null}
{
"error": {
"message": "Rate limit reached for deepseek-v4.1-flash in organization 3f2c... on requests per min (RPM): Limit 300, Used 300, Requested 1. Please try again in 37s.",
"type": "rate_limit_error",
"param": null,
"code": "requests_per_minute_exceeded"
}
}
```
| `error.code` | What happened | What to do |
| - | - | - |
| `requests_per_minute_exceeded` | Too many requests this minute | Wait for `Retry-After`, then retry. |
| `tokens_per_minute_exceeded` | Too many tokens this minute | Wait for `Retry-After`, then retry. If there is no `Retry-After`, this request alone is over your limit: reduce the input or `max_tokens`. |
| `concurrency_limit_exceeded` | Too many requests in progress | Retry after `Retry-After`, or when one of your requests finishes. |
Rejected requests still count toward your requests per minute, so retrying in a tight loop keeps you limited. Batch jobs use the same limits as your synchronous calls. To raise a limit, contact support.
## Set timeouts and retries
Three rules cover almost every case:
1. **Set a per-request timeout** so a stalled connection can't hang your worker.
2. **Retry only the transient codes** (`408`, `429`, `5xx`) and network failures - never `401`, `403`, or `400`.
3. **Back off exponentially with jitter**, cap the delay, cap the attempts, and honor the `Retry-After` header on `429`.
### Using the OpenAI SDK (recommended)
If you call ZeroGPU through the [drop-in OpenAI client](/), timeouts and retries are built in - set `timeout` and `max_retries` once on the client. The SDK retries `408`, `409`, `429`, and `5xx` with exponential backoff and respects `Retry-After` automatically.
```python Python wrap theme={null}
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.zerogpu.ai/v1",
api_key="unused", # ZeroGPU authenticates via the headers below
default_headers={
"x-api-key": os.environ["ZEROGPU_API_KEY"],
"x-project-id": os.environ["ZEROGPU_PROJECT_ID"],
},
timeout=30.0, # seconds, per request
max_retries=5, # exponential backoff on 408 / 409 / 429 / 5xx
)
resp = client.responses.create(
model="llama-3.1-8b-instruct-fast",
input="Your input text here...",
)
print(resp.output)
```
```javascript JavaScript wrap theme={null}
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'https://api.zerogpu.ai/v1',
apiKey: 'unused', // ZeroGPU authenticates via the headers below
defaultHeaders: {
'x-api-key': process.env.ZEROGPU_API_KEY,
'x-project-id': process.env.ZEROGPU_PROJECT_ID,
},
timeout: 30_000, // ms, per request
maxRetries: 5, // exponential backoff on 408 / 409 / 429 / 5xx
});
const resp = await client.responses.create({
model: 'llama-3.1-8b-instruct-fast',
input: 'Your input text here...',
});
console.log(resp.output);
```
You can override either value per request, for example a longer timeout on a heavy call: `client.responses.create(..., timeout=60.0)`.
### Rolling your own
When you call the HTTP API directly, implement the loop yourself: a per-request timeout, a retriable-status check, and exponential backoff with jitter that honors `Retry-After`.
```bash cURL wrap theme={null}
# curl's built-in --retry handles 408/429/500/502/503/504 with exponential
# backoff and honors Retry-After. It does NOT retry 401/403/400 - exactly right.
curl --retry 5 --retry-delay 1 --max-time 30 \
https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: $ZEROGPU_API_KEY" \
-H "x-project-id: $ZEROGPU_PROJECT_ID" \
-d '{
"model": "llama-3.1-8b-instruct-fast",
"input": "Your input text here..."
}'
```
```python Python wrap theme={null}
import os
import random
import time
import requests
URL = "https://api.zerogpu.ai/v1/responses"
RETRIABLE = {408, 429, 500, 502, 503, 504}
HEADERS = {
"content-type": "application/json",
"x-api-key": os.environ["ZEROGPU_API_KEY"],
"x-project-id": os.environ["ZEROGPU_PROJECT_ID"],
}
def create_response(payload, max_retries=5, timeout=30):
for attempt in range(max_retries + 1):
retry_after = None
try:
resp = requests.post(URL, json=payload, headers=HEADERS, timeout=timeout)
if resp.status_code not in RETRIABLE:
resp.raise_for_status() # raises on 401 / 403 / 400 - no retry
return resp.json()
if attempt == max_retries:
resp.raise_for_status()
retry_after = resp.headers.get("retry-after")
except requests.exceptions.RequestException:
if attempt == max_retries:
raise
# exponential backoff with jitter; honor Retry-After on 429
delay = float(retry_after) if retry_after else min(2 ** attempt, 30) + random.random()
time.sleep(delay)
```
```javascript JavaScript wrap theme={null}
const URL = 'https://api.zerogpu.ai/v1/responses';
const RETRIABLE = new Set([408, 429, 500, 502, 503, 504]);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function createResponse(payload, { maxRetries = 5, timeoutMs = 30_000 } = {}) {
const headers = {
'content-type': 'application/json',
'x-api-key': process.env.ZEROGPU_API_KEY,
'x-project-id': process.env.ZEROGPU_PROJECT_ID,
};
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const res = await fetch(URL, {
method: 'POST',
headers,
body: JSON.stringify(payload),
signal: controller.signal,
});
if (!RETRIABLE.has(res.status)) {
if (!res.ok) throw new Error(`ZeroGPU ${res.status}: ${await res.text()}`); // 401 / 403 / 400
return res.json();
}
if (attempt === maxRetries) throw new Error(`ZeroGPU ${res.status} after ${maxRetries} retries`);
// exponential backoff with jitter; honor Retry-After on 429
const retryAfter = res.headers.get('retry-after');
const delay = retryAfter
? Number(retryAfter) * 1000
: Math.min(2 ** attempt * 1000, 30_000) + Math.random() * 1000;
await sleep(delay);
} catch (err) {
if (attempt === maxRetries) throw err;
await sleep(Math.min(2 ** attempt * 1000, 30_000) + Math.random() * 1000);
} finally {
clearTimeout(timer);
}
}
}
```
```rust Rust wrap theme={null}
use reqwest::Client;
use serde_json::Value;
use std::time::Duration;
use tokio::time::sleep;
const RETRIABLE: [u16; 6] = [408, 429, 500, 502, 503, 504];
async fn create_response(payload: Value, max_retries: u32) -> Result> {
let client = Client::builder().timeout(Duration::from_secs(30)).build()?;
let api_key = std::env::var("ZEROGPU_API_KEY")?;
let project_id = std::env::var("ZEROGPU_PROJECT_ID")?;
for attempt in 0..=max_retries {
let mut retry_after: Option = None;
match client
.post("https://api.zerogpu.ai/v1/responses")
.header("content-type", "application/json")
.header("x-api-key", &api_key)
.header("x-project-id", &project_id)
.json(&payload)
.send()
.await
{
Ok(resp) => {
let status = resp.status();
if !RETRIABLE.contains(&status.as_u16()) {
if !status.is_success() {
// 401 / 403 / 400 - permanent, do not retry
return Err(format!("zerogpu {}: {}", status, resp.text().await?).into());
}
return Ok(resp.json().await?);
}
if attempt == max_retries {
return Err(format!("zerogpu {} after {} retries", status, max_retries).into());
}
retry_after = resp
.headers()
.get("retry-after")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse().ok());
}
Err(err) => {
if attempt == max_retries {
return Err(err.into());
}
}
}
// exponential backoff; honor Retry-After on 429
let backoff = retry_after.unwrap_or_else(|| 2u64.pow(attempt).min(30));
sleep(Duration::from_secs(backoff)).await;
}
unreachable!()
}
```
```go Go wrap theme={null}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"math"
"math/rand"
"net/http"
"os"
"strconv"
"time"
)
var retriable = map[int]bool{408: true, 429: true, 500: true, 502: true, 503: true, 504: true}
func createResponse(payload map[string]any, maxRetries int) ([]byte, error) {
body, _ := json.Marshal(payload)
client := &http.Client{Timeout: 30 * time.Second}
for attempt := 0; ; attempt++ {
req, _ := http.NewRequest("POST", "https://api.zerogpu.ai/v1/responses", bytes.NewReader(body))
req.Header.Set("content-type", "application/json")
req.Header.Set("x-api-key", os.Getenv("ZEROGPU_API_KEY"))
req.Header.Set("x-project-id", os.Getenv("ZEROGPU_PROJECT_ID"))
res, err := client.Do(req)
if err == nil && !retriable[res.StatusCode] {
defer res.Body.Close()
data, _ := io.ReadAll(res.Body)
if res.StatusCode >= 400 { // 401 / 403 / 400 - permanent
return nil, fmt.Errorf("zerogpu %d: %s", res.StatusCode, data)
}
return data, nil
}
if attempt >= maxRetries {
if err != nil {
return nil, err
}
return nil, fmt.Errorf("zerogpu %d after %d retries", res.StatusCode, maxRetries)
}
// exponential backoff with jitter; honor Retry-After on 429
delay := time.Duration(math.Min(math.Pow(2, float64(attempt)), 30))*time.Second +
time.Duration(rand.Intn(1000))*time.Millisecond
if err == nil {
if ra := res.Header.Get("Retry-After"); ra != "" {
if secs, e := strconv.Atoi(ra); e == nil {
delay = time.Duration(secs) * time.Second
}
}
res.Body.Close()
}
time.Sleep(delay)
}
}
```
```ruby Ruby wrap theme={null}
require 'net/http'
require 'uri'
require 'json'
ENDPOINT = URI('https://api.zerogpu.ai/v1/responses')
RETRIABLE = [408, 429, 500, 502, 503, 504].freeze
def create_response(payload, max_retries: 5, timeout: 30)
http = Net::HTTP.new(ENDPOINT.host, ENDPOINT.port)
http.use_ssl = true
http.open_timeout = timeout
http.read_timeout = timeout
request = Net::HTTP::Post.new(ENDPOINT.request_uri)
request['content-type'] = 'application/json'
request['x-api-key'] = ENV.fetch('ZEROGPU_API_KEY')
request['x-project-id'] = ENV.fetch('ZEROGPU_PROJECT_ID')
request.body = payload.to_json
(0..max_retries).each do |attempt|
delay =
begin
response = http.request(request)
status = response.code.to_i
unless RETRIABLE.include?(status)
raise "ZeroGPU #{status}: #{response.body}" if status >= 400 # 401 / 403 / 400
return JSON.parse(response.body)
end
raise "ZeroGPU #{status} after #{max_retries} retries" if attempt == max_retries
# exponential backoff with jitter; honor Retry-After on 429
response['retry-after']&.to_f || [2**attempt, 30].min + rand
rescue Net::OpenTimeout, Net::ReadTimeout
raise if attempt == max_retries
[2**attempt, 30].min + rand
end
sleep(delay)
end
end
```
## Use the Batch API for large jobs
For large, non-real-time workloads, the [Batch and Files API](/docs/batch) is the right tool instead of looping over the synchronous endpoint. It processes up to 50,000 requests within a 24-hour window at a discounted rate and sidesteps per-request rate limits entirely - so you don't need a retry loop at all.
| You need… | Use |
| - | - |
| A single immediate response | The synchronous endpoint (`POST /v1/responses`) with the retry loop above |
| Thousands of completions, can wait minutes-to-hours | The [Batch API](/docs/batch) |
| To avoid per-second rate limits during a backfill | The [Batch API](/docs/batch) |
| Streaming responses | The synchronous endpoint - streaming is **not** supported in batch mode |
## Next steps
# Quickstart
Source: https://docs.zerogpu.ai/docs/quickstart
First API call in minutes.
## 1. Grab your credentials
Log into the [ZeroGPU dashboard](https://platform.zerogpu.ai/dashboard) and copy these three values:
| Credential | Where to find it |
| - | - |
| **API Key** | Dashboard → API Keys |
| **Project ID** (optional) | Dashboard → Project Settings - scopes requests to a project |
| **Model** | Dashboard → Model selector, or pick one from the [Model Catalog](/docs/model-catalog) |
## 2. Send a request
```bash cURL wrap theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: $ZEROGPU_API_KEY" \
-H "x-project-id: $ZEROGPU_PROJECT_ID" \
-d '{
"model": "YOUR_MODEL",
"input": "Your input text here..."
}'
```
```python Python wrap theme={null}
# pip install zerogpu-api
import os
from zerogpu import ZerogpuApi
client = ZerogpuApi(
api_key=os.environ["ZEROGPU_API_KEY"],
project_id=os.environ["ZEROGPU_PROJECT_ID"],
)
response = client.responses.create_response(
model="YOUR_MODEL",
input="Your input text here...",
)
print(response)
```
```javascript JavaScript wrap theme={null}
// npm install zerogpu-api
import { ZerogpuApiClient } from 'zerogpu-api';
const client = new ZerogpuApiClient({
apiKey: process.env.ZEROGPU_API_KEY,
projectId: process.env.ZEROGPU_PROJECT_ID,
});
const response = await client.responses.createResponse({
model: 'YOUR_MODEL',
input: 'Your input text here...',
});
console.log(response.output);
```
```rust Rust wrap theme={null}
use reqwest::Client;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box> {
let client = Client::new();
let payload = json!({
"model": "YOUR_MODEL",
"input": "Your input text here..."
});
let response = client
.post("https://api.zerogpu.ai/v1/responses")
.header("content-type", "application/json")
.header("x-api-key", "YOUR_API_KEY")
.header("x-project-id", "YOUR_PROJECT_ID")
.json(&payload)
.send()
.await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
```
```go Go wrap theme={null}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.zerogpu.ai/v1/responses"
payload := map[string]any{
"model": "YOUR_MODEL",
"input": "Your input text here...",
}
payloadBytes, err := json.Marshal(payload)
if err != nil {
panic(err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payloadBytes))
if err != nil {
panic(err)
}
req.Header.Set("content-type", "application/json")
req.Header.Set("x-api-key", "YOUR_API_KEY")
req.Header.Set("x-project-id", "YOUR_PROJECT_ID")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
```
```ruby Ruby wrap theme={null}
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://api.zerogpu.ai/v1/responses')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
request = Net::HTTP::Post.new(uri.request_uri)
request['content-type'] = 'application/json'
request['x-api-key'] = 'YOUR_API_KEY'
request['x-project-id'] = 'YOUR_PROJECT_ID'
request.body = {
model: 'YOUR_MODEL',
input: 'Your input text here...'
}.to_json
response = http.request(request)
puts response.body
```
Store your API key in environment variables. Never commit it to version control or expose it in client-side code.
## 3. See a complete example
A full request - here the `llama-3.1-8b-instruct-fast` model summarizing a passage:
```bash cURL wrap theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: $ZEROGPU_API_KEY" \
-H "x-project-id: $ZEROGPU_PROJECT_ID" \
-d '{
"model": "llama-3.1-8b-instruct-fast",
"input": "NASA announced that its Artemis III mission is now scheduled for late 2026, marking the first time astronauts will land on the lunar surface since Apollo 17 in 1972. The mission will send a crew of four to the Moon aboard the Orion spacecraft, with two astronauts descending to the south pole using SpaceX Starship as a lunar lander. Scientists are particularly excited about exploring permanently shadowed craters that may contain water ice, which could be critical for sustaining long-term human presence on the Moon."
}'
```
```python Python wrap theme={null}
# pip install zerogpu-api
import os
from zerogpu import ZerogpuApi
client = ZerogpuApi(
api_key=os.environ["ZEROGPU_API_KEY"],
project_id=os.environ["ZEROGPU_PROJECT_ID"],
)
response = client.responses.create_response(
model="llama-3.1-8b-instruct-fast",
input="NASA announced that its Artemis III mission is now scheduled for late 2026, marking the first time astronauts will land on the lunar surface since Apollo 17 in 1972. The mission will send a crew of four to the Moon aboard the Orion spacecraft, with two astronauts descending to the south pole using SpaceX Starship as a lunar lander. Scientists are particularly excited about exploring permanently shadowed craters that may contain water ice, which could be critical for sustaining long-term human presence on the Moon.",
)
print(response)
```
```javascript JavaScript wrap theme={null}
// npm install zerogpu-api
import { ZerogpuApiClient } from 'zerogpu-api';
const client = new ZerogpuApiClient({
apiKey: process.env.ZEROGPU_API_KEY,
projectId: process.env.ZEROGPU_PROJECT_ID,
});
const response = await client.responses.createResponse({
model: 'llama-3.1-8b-instruct-fast',
input: 'NASA announced that its Artemis III mission is now scheduled for late 2026, marking the first time astronauts will land on the lunar surface since Apollo 17 in 1972. The mission will send a crew of four to the Moon aboard the Orion spacecraft, with two astronauts descending to the south pole using SpaceX Starship as a lunar lander. Scientists are particularly excited about exploring permanently shadowed craters that may contain water ice, which could be critical for sustaining long-term human presence on the Moon.',
});
console.log(response.output);
```
```rust Rust wrap theme={null}
use reqwest::Client;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box> {
let client = Client::new();
let payload = json!({
"model": "llama-3.1-8b-instruct-fast",
"input": "NASA announced that its Artemis III mission is now scheduled for late 2026, marking the first time astronauts will land on the lunar surface since Apollo 17 in 1972. The mission will send a crew of four to the Moon aboard the Orion spacecraft, with two astronauts descending to the south pole using SpaceX Starship as a lunar lander. Scientists are particularly excited about exploring permanently shadowed craters that may contain water ice, which could be critical for sustaining long-term human presence on the Moon."
});
let response = client
.post("https://api.zerogpu.ai/v1/responses")
.header("content-type", "application/json")
.header("x-api-key", "YOUR_API_KEY")
.header("x-project-id", "YOUR_PROJECT_ID")
.json(&payload)
.send()
.await?;
let body = response.text().await?;
println!("{}", body);
Ok(())
}
```
```go Go wrap theme={null}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.zerogpu.ai/v1/responses"
payload := map[string]any{
"model": "llama-3.1-8b-instruct-fast",
"input": "NASA announced that its Artemis III mission is now scheduled for late 2026, marking the first time astronauts will land on the lunar surface since Apollo 17 in 1972. The mission will send a crew of four to the Moon aboard the Orion spacecraft, with two astronauts descending to the south pole using SpaceX Starship as a lunar lander. Scientists are particularly excited about exploring permanently shadowed craters that may contain water ice, which could be critical for sustaining long-term human presence on the Moon.",
}
payloadBytes, err := json.Marshal(payload)
if err != nil {
panic(err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payloadBytes))
if err != nil {
panic(err)
}
req.Header.Set("content-type", "application/json")
req.Header.Set("x-api-key", "YOUR_API_KEY")
req.Header.Set("x-project-id", "YOUR_PROJECT_ID")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
```
```ruby Ruby wrap theme={null}
require 'net/http'
require 'uri'
require 'json'
uri = URI.parse('https://api.zerogpu.ai/v1/responses')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
request = Net::HTTP::Post.new(uri.request_uri)
request['content-type'] = 'application/json'
request['x-api-key'] = 'YOUR_API_KEY'
request['x-project-id'] = 'YOUR_PROJECT_ID'
request.body = {
model: 'llama-3.1-8b-instruct-fast',
input: 'NASA announced that its Artemis III mission is now scheduled for late 2026, marking the first time astronauts will land on the lunar surface since Apollo 17 in 1972. The mission will send a crew of four to the Moon aboard the Orion spacecraft, with two astronauts descending to the south pole using SpaceX Starship as a lunar lander. Scientists are particularly excited about exploring permanently shadowed craters that may contain water ice, which could be critical for sustaining long-term human presence on the Moon.'
}.to_json
response = http.request(request)
puts response.body
```
🎉 The model returns the summary:
```text wrap theme={null}
NASA's Artemis III mission is now scheduled for late 2026, marking the first lunar landing since Apollo 17 in 1972, with a crew of four astronauts aboard the Orion spacecraft, including two descending to the Moon's south pole using SpaceX Starship as a lunar lander to explore permanently shadowed craters potentially containing water ice crucial for sustaining a long-term human presence on the Moon.
```
## 4. Verify it worked
Check the dashboard:
* **Logs**: your request appears with model, status, and latency.
* **Usage**: token counts update in real time.
If you get a `401`, your API key is wrong. A `403` means a bad project ID.
## Next steps
# Text Classification
Source: https://docs.zerogpu.ai/docs/text-classification
Edge models that map text to labels, IAB taxonomy, and audience signals.
Text classification models map a passage to predefined labels or categories. ZeroGPU offers IAB taxonomy classifiers tuned for ad tech, a general zero-shot classifier where you supply the candidate labels, and the schema-based GLiNER2.5 models, which classify, extract entities, fill a JSON schema, and make dynamic-label decisions such as intent and routing from the same request. Each request is shown for both the [Responses API](/api-reference/responses) and the OpenAI-compatible [Chat Completions API](/api-reference/chat-completions).
| Model | Input /1M | Output /1M | Max tokens |
| - | -: | -: | -: |
|
zlm-v1-iab-classify-edge | \$0.02 | \$0.05 | 400 |
|
zlm-v2-iab-classify-edge-enriched | \$0.05 | \$0.15 | 800 |
|
zlm-v1-iab-domain-classifier | \$0.02 | \$0.05 | 100 |
|
deberta-v3-small | \$0.02 | \$0.05 | 400 |
|
zlm-v1-signal-extract | \$0.04 | \$0.10 | 400 |
|
gliner2.5-base-v1 | \$0.02 | \$0.05 | — |
|
gliner2.5-multi-v1 | \$0.02 | \$0.05 | — |
|
gliner2.5-decide-v1 | \$0.004 | Not billed | — |
## zlm-v1-iab-classify-edge
> ZeroGPU's IAB classifier maps any text to the industry-standard IAB Content Taxonomy in a single, fast inference call. Each call returns categories across both the 1.0 and 2.2 taxonomies plus matched audience segments, every result scored for confidence. With support for 50+ languages, it classifies multilingual content without a translation step. At 90M parameters on ONNX, it's built for the high-volume, sub-millisecond classification that ad tech and content platforms demand, right at the edge. When you need clean category and audience signals on every request, this is the model — and when you need the full profile, reach for the enriched variant.
**References:** [Model docs](https://docs.zerogpu.ai/) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Technology has quietly reshaped the rhythm of everyday life, weaving itself into routines so seamlessly that it often goes unnoticed. From the moment a smartphone alarm wakes someone in the morning to the final glance at a glowing screen before sleep, digital systems guide communication, navigation, work, and entertainment. This transformation did not happen overnight. It emerged through decades of incremental innovation, each new tool building upon the last, until the modern world became deeply interconnected.One of the most significant changes has been the speed at which information travels.",
"model": "zlm-v1-iab-classify-edge"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-iab-classify-edge",
"messages": [
{
"role": "user",
"content": "What are the basics of exercise and physical fitness?Exercise is anything that gets your body moving. Regular exercise is one of the best things you can do for your health. It has many benefits, including improving your overall health and fitness, and reducing your risk for many chronic (long-term) diseases.Every physical fitness routine is built on a few simple ideas. These include:Make exercise a habit, as your body adapts to the type of activity you do most often. Regular practice will help you improve.Build up your activity level slowly to help you continue to get stronger, faster, or more flexible without pushing too hard all at once.Challenge yourself by lifting slightly heavier weights, adding a few more minutes to your walk, or increasing your pace."
}
]
}'
```
Returns IAB `audience` categories plus `content` matches across taxonomy versions, each with a confidence score.
```json Response theme={null}
{
"audience": [
{ "name": "Technology & Computing", "score": 0.7686 },
{ "name": "Consumer Electronics", "score": 0.7206 },
{ "name": "65-69", "score": 0.5950 }
],
"content": {
"iab_1_0": [
{ "name": "Cell Phones", "score": 0.7597 },
{ "name": "Technology & Computing", "score": 0.7387 }
],
"iab_2_2": [
{ "name": "Smartphones", "score": 0.7597 },
{ "name": "Wearable Technology", "score": 0.7387 },
{ "name": "Technology & Computing", "score": 0.7109 }
]
}
}
```
## zlm-v2-iab-classify-edge-enriched
> The enriched variant of ZeroGPU's IAB classifier turns a single inference call into a full content-intelligence profile not just a label, but everything a contextual pipeline needs to act on. Each call returns IAB categories across both the 1.0 and 2.2 taxonomies (down to tier-3), audience and interest segments, topics, keywords, and user-intent classification — all with confidence scores with edge-native, sub-millisecond speeds. With support for 50+ languages, it delivers the same full profile on multilingual content without a translation step. Built for contextual ad targeting, brand-safety scoring, publisher content categorization, and signal pipelines that need full metadata on every request.
**References:** [Model docs](https://docs.zerogpu.ai/) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Technology has quietly reshaped the rhythm of everyday life, weaving itself into routines so seamlessly that it often goes unnoticed. From the moment a smartphone alarm wakes someone in the morning to the final glance at a glowing screen before sleep, digital systems guide communication, navigation, work, and entertainment. This transformation did not happen overnight. It emerged through decades of incremental innovation, each new tool building upon the last, until the modern world became deeply interconnected.One of the most significant changes has been the speed at which information travels.",
"model": "zlm-v2-iab-classify-edge-enriched"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v2-iab-classify-edge-enriched",
"messages": [
{
"role": "user",
"content": "What are the basics of exercise and physical fitness?Exercise is anything that gets your body moving. Regular exercise is one of the best things you can do for your health. It has many benefits, including improving your overall health and fitness, and reducing your risk for many chronic (long-term) diseases.Every physical fitness routine is built on a few simple ideas. These include:Make exercise a habit, as your body adapts to the type of activity you do most often. Regular practice will help you improve.Build up your activity level slowly to help you continue to get stronger, faster, or more flexible without pushing too hard all at once.Challenge yourself by lifting slightly heavier weights, adding a few more minutes to your walk, or increasing your pace."
}
]
}'
```
In addition to scored `audience` and `content` categories, the enriched model returns taxonomy codes and parent IDs, plus `topics`, `keywords`, and an inferred `user_intent`.
```json Response theme={null}
{
"audience": [
{
"id": 687,
"parent_id": 206,
"name": "Technology & Computing",
"tier1_name": "Interest",
"tier2_name": "Technology & Computing",
"score": 0.7686
},
{
"id": 703,
"parent_id": 687,
"name": "Consumer Electronics",
"tier1_name": "Interest",
"tier2_name": "Technology & Computing",
"tier3_name": "Consumer Electronics",
"score": 0.7206
}
],
"content": {
"iab_1_0": [
{ "code": "IAB19-6", "name": "Cell Phones", "tier": 2, "parent_code": "IAB19", "score": 0.7597 },
{ "code": "IAB19", "name": "Technology & Computing", "tier": 1, "parent_code": null, "score": 0.7387 }
]
},
"topics": [
{ "name": "smartphones", "score": 0.7597 },
{ "name": "wearable technology", "score": 0.7387 },
{ "name": "technology & computing", "score": 0.7109 }
],
"keywords": ["technology", "reshaped", "everyday", "routines", "quietly", "weaving", "rhythm", "itself", "life", "into"],
"user_intent": {
"name": "mastering technology quietly reshaped rhythm everyday life",
"category": "informational",
"score": 0.5
}
}
```
## zlm-v1-iab-domain-classifier
> ZeroGPU's Domain IAB Classifier maps a raw domain name straight to the IAB Content Taxonomy in a single, fast inference call, returning content categories, topics, keywords, and user-intent signals. Where the page-level IAB classifiers take the full body of an article as input, this model takes only the domain (for example `nytimes.com`), reducing payload size by up to 10x while still surfacing the contextual signals that bidstream enrichment, contextual targeting, and domain-level intelligence pipelines run on. At 149M parameters on ONNX, it's built for the high-volume, sub-millisecond classification that ad tech and content platforms demand, right at the edge.
**References:** [Model docs](https://docs.zerogpu.ai/) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "nytimes.com",
"model": "zlm-v1-iab-domain-classifier"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-iab-domain-classifier",
"messages": [
{
"role": "user",
"content": "nytimes.com"
}
]
}'
```
Returns scored `content` categories across taxonomy versions plus `topics`, `keywords`, and an inferred `user_intent` for the domain.
```json Response theme={null}
{
"content": {
"iab_1_0": [
{ "name": "News", "score": 0.8124 },
{ "name": "Politics", "score": 0.6533 }
],
"iab_2_2": [
{ "name": "News and Politics", "score": 0.8124 },
{ "name": "Business and Finance", "score": 0.5980 }
]
},
"topics": [
{ "name": "news", "score": 0.8124 },
{ "name": "journalism", "score": 0.6740 },
{ "name": "current events", "score": 0.6533 }
],
"keywords": ["news", "politics", "world", "business", "opinion", "media", "journalism"],
"user_intent": {
"name": "reading news and current events",
"category": "informational",
"score": 0.5
}
}
```
## deberta-v3-small
> Microsoft's DeBERTa-v3-small is a fast, lightweight zero-shot text classifier for high-volume routing, filtering, and tagging. Hand it any text alongside your own candidate labels and it returns a confidence score for each. No training data and no fixed taxonomy, just the categories you define at request time. Because it scores every label rather than forcing one choice, you get soft probabilities to threshold, rank, or route on however your pipeline needs. Purpose-built and CPU-optimized, it runs faster and cheaper than asking a general-purpose frontier model to classify.
**References:** [Model docs](https://github.com/microsoft/DeBERTa/tree/master/docs) • [Terms](https://github.com/microsoft/DeBERTa/blob/master/SECURITY.md) • [Privacy](https://github.com/microsoft/DeBERTa/blob/master/LICENSE)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "deberta-v3-small",
"input": "Apple is expected to unveil its next-generation M5 chip at WWDC this June, promising a 40% boost in GPU performance and a new dedicated AI core for on-device machine learning tasks.",
"instructions": "[sports, finance, politics, technology]"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "deberta-v3-small",
"messages": [
{
"role": "system",
"content": "[sports, finance, politics, technology]"
},
{
"role": "user",
"content": "Apple is expected to unveil its next-generation M5 chip at WWDC this June, promising a 40% boost in GPU performance and a new dedicated AI core for on-device machine learning tasks."
}
]
}'
```
Returns each candidate label with a probability score.
```json Response theme={null}
{
"technology": 0.971784,
"politics": 0.011858,
"sports": 0.01175,
"finance": 0.004608
}
```
## zlm-v1-signal-extract
> ZeroGPU's signal extractor turns unstructured text into structured signals that downstream systems can act on. One inference call returns topics, keywords, intent, and other contextual attributes as structured output, so content enrichment, contextual intelligence, ad targeting, agent routing, recommendation systems, and analytics pipelines all read from the same pass. At 80M parameters it is built for high-volume workloads where a general-purpose LLM is more machinery than the job needs.
**References:** [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
Pass the signal categories you want in `categories`; `max_keywords` caps how many keywords come back.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-signal-extract",
"input": "How can I pay using my credit card?",
"categories": [
"signals"
]
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "zlm-v1-signal-extract",
"messages": [
{
"role": "user",
"content": "How can I pay using my credit card?"
}
],
"categories": [
"signals"
],
"max_keywords": 6
}'
```
The signals arrive as a JSON string in the output text. Parsed:
```json Response theme={null}
{
"keywords": [
"credit card",
"login",
"official website",
"account access"
],
"user_intent": {
"name": "pay using credit card",
"category": "navigational",
"score": 0.95
}
}
```
## gliner2.5-base-v1
> Fastino's GLiNER2.5 Base is an English schema-based information extraction model built on DeBERTa-v3-base. A single model covers entity extraction, text classification, structured record extraction, relation extraction, and span-level attributes — you supply a label set or a schema at inference time instead of fine-tuning one model per task. It fits GTM workflows such as parsing inbound leads, extracting company and contact details, classifying sales conversations, identifying relationships between people and companies, structuring CRM notes, and enriching customer or account data.
**References:** [Model docs](https://huggingface.co/fastino/gliner2.5-base-v1) • [Terms](https://github.com/fastino-ai/GLiNER2/blob/main/LICENSE) • [Privacy](https://github.com/fastino-ai/GLiNER2/blob/main/LICENSE)
### Entity Extraction
Set `metadata.usecase` to `ner` and pass your own `labels` to extract named entities. `threshold` sets the minimum confidence for a span to be returned.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "The application is built with Python 3.11 and uses PostgreSQL 15 for storage. It runs on Kubernetes with Docker containers and communicates via gRPC.",
"model": "gliner2.5-base-v1",
"metadata": {
"labels": [
"programming language",
"database",
"technology",
"protocol"
],
"usecase": "ner",
"threshold": 0.3
}
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gliner2.5-base-v1",
"messages": [
{
"role": "user",
"content": "The application is built with Python 3.11 and uses PostgreSQL 15 for storage. It runs on Kubernetes with Docker containers and communicates via gRPC."
}
],
"metadata": {
"labels": [
"programming language",
"database",
"technology",
"protocol"
],
"usecase": "ner",
"threshold": 0.3
}
}'
```
### Structured Data Extraction
Set `metadata.usecase` to `json` and define a `schema` of `field::type::description` entries to pull structured records out of free text.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Best regards, John Smith, Senior Software Engineer at Acme Corp. Phone: (555) 123-4567, Email: john.smith@acme.com, Office: 123 Main Street, Suite 400, San Francisco, CA 94105",
"model": "gliner2.5-base-v1",
"metadata": {
"schema": {
"contact": [
"name::str::Full name",
"title::str::Job title",
"company::str::Company name",
"phone::str::Phone number",
"email::str::Email address",
"address::str::Office address"
]
},
"usecase": "json"
}
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gliner2.5-base-v1",
"messages": [
{
"role": "user",
"content": "Best regards, John Smith, Senior Software Engineer at Acme Corp. Phone: (555) 123-4567, Email: john.smith@acme.com, Office: 123 Main Street, Suite 400, San Francisco, CA 94105"
}
],
"metadata": {
"schema": {
"contact": [
"name::str::Full name",
"title::str::Job title",
"company::str::Company name",
"phone::str::Phone number",
"email::str::Email address",
"address::str::Office address"
]
},
"usecase": "json"
}
}'
```
### Text Classification
Set `metadata.usecase` to `classification` and supply a `schema` mapping each axis to its allowed labels.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "I absolutely love this product! The quality is outstanding and the customer service was incredibly helpful.",
"model": "gliner2.5-base-v1",
"metadata": {
"schema": {
"sentiment": [
"positive",
"negative",
"neutral"
]
},
"usecase": "classification"
}
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gliner2.5-base-v1",
"messages": [
{
"role": "user",
"content": "I absolutely love this product! The quality is outstanding and the customer service was incredibly helpful."
}
],
"metadata": {
"schema": {
"sentiment": [
"positive",
"negative",
"neutral"
]
},
"usecase": "classification"
}
}'
```
## gliner2.5-multi-v1
> Fastino's GLiNER2.5 Multi is a 287M-parameter multilingual information extraction model built on mDeBERTa-v3-base. It supports zero-shot named entity recognition, text classification, and structured JSON extraction across multiple languages, so it can pull people, organizations, locations, attributes, and other custom entities out of text without task-specific retraining.
**References:** [Model docs](https://huggingface.co/fastino/gliner2.5-multi-v1) • [Terms](https://github.com/fastino-ai/GLiNER2/blob/main/LICENSE) • [Privacy](https://github.com/fastino-ai/GLiNER2/blob/main/LICENSE)
### Entity Extraction
Set `metadata.usecase` to `ner` and pass your own `labels` to extract named entities. `threshold` sets the minimum confidence for a span to be returned.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "The application is built with Python 3.11 and uses PostgreSQL 15 for storage. It runs on Kubernetes with Docker containers and communicates via gRPC.",
"model": "gliner2.5-multi-v1",
"metadata": {
"labels": [
"programming language",
"database",
"technology",
"protocol"
],
"usecase": "ner",
"threshold": 0.3
}
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gliner2.5-multi-v1",
"messages": [
{
"role": "user",
"content": "The application is built with Python 3.11 and uses PostgreSQL 15 for storage. It runs on Kubernetes with Docker containers and communicates via gRPC."
}
],
"metadata": {
"labels": [
"programming language",
"database",
"technology",
"protocol"
],
"usecase": "ner",
"threshold": 0.3
}
}'
```
### Structured Data Extraction
Set `metadata.usecase` to `json` and define a `schema` of `field::type::description` entries to pull structured records out of free text.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Best regards, John Smith, Senior Software Engineer at Acme Corp. Phone: (555) 123-4567, Email: john.smith@acme.com, Office: 123 Main Street, Suite 400, San Francisco, CA 94105",
"model": "gliner2.5-multi-v1",
"metadata": {
"schema": {
"contact": [
"name::str::Full name",
"title::str::Job title",
"company::str::Company name",
"phone::str::Phone number",
"email::str::Email address",
"address::str::Office address"
]
},
"usecase": "json"
}
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gliner2.5-multi-v1",
"messages": [
{
"role": "user",
"content": "Best regards, John Smith, Senior Software Engineer at Acme Corp. Phone: (555) 123-4567, Email: john.smith@acme.com, Office: 123 Main Street, Suite 400, San Francisco, CA 94105"
}
],
"metadata": {
"schema": {
"contact": [
"name::str::Full name",
"title::str::Job title",
"company::str::Company name",
"phone::str::Phone number",
"email::str::Email address",
"address::str::Office address"
]
},
"usecase": "json"
}
}'
```
### Text Classification
Set `metadata.usecase` to `classification` and supply a `schema` mapping each axis to its allowed labels.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "I absolutely love this product! The quality is outstanding and the customer service was incredibly helpful.",
"model": "gliner2.5-multi-v1",
"metadata": {
"schema": {
"sentiment": [
"positive",
"negative",
"neutral"
]
},
"usecase": "classification"
}
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gliner2.5-multi-v1",
"messages": [
{
"role": "user",
"content": "I absolutely love this product! The quality is outstanding and the customer service was incredibly helpful."
}
],
"metadata": {
"schema": {
"sentiment": [
"positive",
"negative",
"neutral"
]
},
"usecase": "classification"
}
}'
```
## gliner2.5-decide-v1
> Fastino's GLiNER2.5 Decide is a 486M-parameter zero-shot decision and classification model built for operational AI workflows. You supply the labels or decision options at request time to classify intent, route agents and tools, triage support requests, make moderation decisions, detect completion, and determine when a request needs human handoff. It handles single-label, multi-label, and several decision heads in one call, which suits high-volume routing and decision workloads where speed and structured outputs matter.
**References:** [Model docs](https://huggingface.co/fastino/GLiNER2.5-Decide) • [Terms](https://github.com/fastino-ai/GLiNER2/blob/main/LICENSE) • [Privacy](https://github.com/fastino-ai/GLiNER2/blob/main/LICENSE)
### Decision / Routing
Set `metadata.usecase` to `decide` and pass a `labels` map of decision heads to their allowed options. Every head is answered in the same call, so one request can return an intent and a handoff verdict together.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "The customer says their payment failed and they want someone to call them.",
"model": "gliner2.5-decide-v1",
"metadata": {
"labels": {
"intent": [
"payment_issue",
"refund",
"account_access",
"general_question"
],
"handoff": [
"yes",
"no"
]
},
"usecase": "decide"
}
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gliner2.5-decide-v1",
"messages": [
{
"role": "user",
"content": "The customer says their payment failed and they want someone to call them."
}
],
"metadata": {
"labels": {
"intent": [
"payment_issue",
"refund",
"account_access",
"general_question"
],
"handoff": [
"yes",
"no"
]
},
"usecase": "decide"
}
}'
```
### Text Classification
Set `metadata.usecase` to `classification` and supply a `schema` mapping each axis to its allowed labels.
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "I absolutely love this product! The quality is outstanding and the customer service was incredibly helpful.",
"model": "gliner2.5-decide-v1",
"metadata": {
"schema": {
"sentiment": [
"positive",
"negative",
"neutral"
]
},
"usecase": "classification"
}
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gliner2.5-decide-v1",
"messages": [
{
"role": "user",
"content": "I absolutely love this product! The quality is outstanding and the customer service was incredibly helpful."
}
],
"metadata": {
"schema": {
"sentiment": [
"positive",
"negative",
"neutral"
]
},
"usecase": "classification"
}
}'
```
# Text Generation
Source: https://docs.zerogpu.ai/docs/text-generation
Edge generative models for conversation and reasoning.
Text generation models produce new text from an input prompt. ZeroGPU offers open-weight heavyweights — DeepSeek's deepseek-v4.1-flash, OpenAI's gpt-oss-120b, Alibaba's qwen3-30b-a3b-fp8 and multimodal qwen3.6-35b-a3b, and Z.ai's glm-5.3-flash — for reasoning and tool use, OpenAI's gpt-5.4-nano, gpt-5.6-luna, and gpt-4.1-mini for cost-efficient high-volume work, plus conversational and reasoning models from Liquid AI, Meta's llama-3.1-8b-instruct-fast for high-volume summarization, and Meta's llama-guard-4-12b for safety classification. Each request is shown for both the [Responses API](/api-reference/responses) and the OpenAI-compatible [Chat Completions API](/api-reference/chat-completions) — except `qwen3-30b-a3b-fp8`, which is Chat Completions only.
| Model | Input /1M | Output /1M | Cached input /1M | Max tokens |
| - | -: | -: | -: | -: |
|
gpt-oss-120b | \$0.15 | \$0.60 | \$0.03 | 131,072 |
|
qwen3-30b-a3b-fp8 | \$0.10 | \$0.45 | \$0.05 | 32,768 |
|
deepseek-v4.1-flash | \$0.30 | \$1.20 | \$0.003 | 1,048,576 |
|
glm-5.3-flash | \$0.10 | \$0.35 | \$0.015 | 1,048,576 |
|
gpt-5.4-nano | \$0.20 | \$1.25 | \$0.02 | 400,000 |
|
gpt-5.6-luna | \$0.20 | \$1.20 | \$0.20 | 272,000 |
|
gpt-4.1-mini | \$0.40 | \$1.60 | \$0.10 | 1,047,576 |
|
llama-3.1-8b-instruct-fast | \$0.15 | \$0.28 | \$0.025 | 131,072 |
|
llama-guard-4-12b | \$0.18 | \$0.18 | — | 163,840 |
|
LFM2.5-1.2B-Instruct | \$0.02 | \$0.05 | — | 32,768 |
|
LFM2.5-1.2B-Thinking | \$0.02 | \$0.05 | — | 32,768 |
|
qwen3.6-35b-a3b | \$0.20 | \$1.50 | \$0.20 | — |
## gpt-oss-120b
> OpenAI's gpt-oss-120b is an open-weight Mixture-of-Experts model with 117B total parameters (5.1B active per token), served on ZeroGPU for general text generation. It reasons through a problem before answering and returns that reasoning trace alongside the final answer, and it supports function calling, batch tasks, and a 131,072-token context window. When a task needs frontier-level reasoning or tool use beyond what the smaller edge models cover, this is the model.
**References:** [Model docs](https://huggingface.co/openai/gpt-oss-120b) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Name my WiFi network something that will make my neighbors laugh. Give me your top 3 with a one-line reason each.",
"model": "gpt-oss-120b",
"max_tokens": 800,
"instructions": "You are a witty naming consultant. Be brief."
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gpt-oss-120b",
"messages": [
{
"role": "system",
"content": "You are a witty naming consultant. Be brief."
},
{
"role": "user",
"content": "Name my WiFi network something that will make my neighbors laugh. Give me your top 3 with a one-line reason each."
}
],
"max_tokens": 800
}'
```
The model reasons before it answers and returns the trace alongside the final text — a `reasoning` output item in Responses, and a `reasoning` field on the message in Chat Completions.
```json Responses API theme={null}
{
"id": "id-1784318124857",
"object": "response",
"created_at": 1784318124,
"model": "gpt-oss-120b",
"status": "completed",
"instructions": "You are a witty naming consultant. Be brief.",
"output": [
{
"id": "rs_8d4dc6f3f33d0d28",
"type": "reasoning",
"content": [
{
"type": "reasoning_text",
"text": "We need to respond with a top 3 WiFi names that will make neighbors laugh, each with a one-line reason. Be witty. Keep brief."
}
]
},
{
"id": "msg_9c3dfbf63445d80a",
"type": "message",
"role": "assistant",
"status": "completed",
"content": [
{
"type": "output_text",
"text": "**1. “FBI Surveillance Van #42”** – Neighbors will double-check the street before they even think about streaming.\n\n**2. “Drop It Like It’s Hotspot”** – A pun that’s so cheesy it’ll have the whole block groaning and giggling.\n\n**3. “Tell My Wi-Fi I Love You”** – Because nothing says “I’m caring” like a reminder that even your router needs affection."
}
]
}
],
"usage": {
"input_tokens": 0,
"output_tokens": 0,
"total_tokens": 0
}
}
```
```json Chat Completions theme={null}
{
"id": "id-1784318142640",
"object": "chat.completion",
"created": 1784318142,
"model": "gpt-oss-120b",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "**1. “Drop It Like It’s Hotspot”** – A cheeky nod to the song that’ll make anyone pause and grin while they log in.\n\n**2. “FBI Surveillance Van #42”** – The classic prank that’ll have neighbors double-checking their curtains.\n\n**3. “Tell My Wi-Fi I’m Sorry”** – Because we all know the neighbor who borrows bandwidth—now they’ll feel the love (and the guilt).",
"reasoning": "We need to give top 3 witty WiFi network names that will make neighbors laugh, with one-line reason each. Be brief.",
"tool_calls": []
}
}
],
"usage": {
"prompt_tokens": 107,
"completion_tokens": 160,
"total_tokens": 267
}
}
```
## qwen3-30b-a3b-fp8
This model supports the Chat Completions API only — the Responses endpoint
(`/v1/responses`) is not available for this model.
> Alibaba's Qwen3-30B-A3B is an open-weight Mixture-of-Experts model with 30.5B total parameters (3.3B active per token), served on ZeroGPU as an FP8 build for efficient inference. It thinks through a problem before answering and returns that reasoning alongside the final text, and it supports function calling, streaming, batch tasks, and 100+ languages with a 32,768-token context window. When you want frontier-style reasoning and tool use in a lighter, multilingual package, this is the model.
**References:** [Model docs](https://huggingface.co/Qwen/Qwen3-30B-A3B-FP8) • [Terms](https://zerogpu.ai/terms) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"model": "qwen3-30b-a3b-fp8",
"messages": [
{
"role": "system",
"content": "You are a pragmatic senior engineer. Be brief."
},
{
"role": "user",
"content": "My API is getting rate-limited by a third party. Give me 3 battle-tested strategies to handle it, one line each."
}
],
"max_tokens": 800
}'
```
The model reasons before it answers and returns the trace alongside the final text as a `reasoning` field on the message.
```json Response theme={null}
{
"id": "id-1784324156320",
"object": "chat.completion",
"created": 1784324156,
"model": "qwen3-30b-a3b-fp8",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "**1. Exponential backoff with jitter** – Retry on 429s with doubling delays plus randomness so your retries don't stampede in sync.\n\n**2. Client-side token bucket** – Throttle your own outbound rate just below the provider's limit so you never hit the wall in the first place.\n\n**3. Cache and coalesce** – Cache hot responses and merge duplicate in-flight requests so repeat calls never reach the third party at all.",
"reasoning": "The user's API is being rate-limited by a third party and wants 3 battle-tested strategies, one line each. The classic answers: exponential backoff with jitter, client-side throttling below the limit, and caching plus request coalescing. Keep each to one line.",
"tool_calls": []
}
}
],
"usage": {
"prompt_tokens": 52,
"completion_tokens": 143,
"total_tokens": 195
}
}
```
## deepseek-v4.1-flash
> DeepSeek's DeepSeek-V4.1-Flash is an open-weight sparse Mixture-of-Experts model and the first built on DeepSeek's Causal Encoder-Decoder (CED) architecture, activating 8B parameters on input and 16B on output, served on ZeroGPU for general text generation. It keeps the 1,048,576-token (1M) context window of the V4 Flash line, which suits large codebases, long documents, extended conversations, and multi-step agent tasks, and supports function calling alongside both fast non-thinking replies and higher-effort reasoning.
**References:** [Model docs](https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash) • [Terms](https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash/blob/main/LICENSE) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Hello!",
"model": "deepseek-v4.1-flash"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "deepseek-v4.1-flash",
"messages": [
{
"role": "system",
"content": "You are a support triage analyst. Be concise."
},
{
"role": "user",
"content": "Classify this ticket by urgency (low/medium/high) and category, then summarize it in one line: '"'"'Our checkout page has been throwing intermittent 502 errors since this morning'"'"'s deploy. Roughly 1 in 5 customers can'"'"'t complete payment, and abandoned carts are spiking. Rolling back didn'"'"'t help."
}
],
"max_tokens": 800
}'
```
The model returns its answer as the assistant message — an `output_text` item in Responses, the `message.content` field in Chat Completions — with `usage` token counts alongside it.
## glm-5.3-flash
> Z.ai's GLM-5.3-Flash is an efficient open-weight model for coding and long-horizon agent tasks, served on ZeroGPU for general text generation. Its hybrid sparse and linear attention keeps long-context behaviour accurate across a 1,048,576-token (1M) window while reducing compute, and it supports function calling and adjustable reasoning effort.
**References:** [Model docs](https://huggingface.co/zai-org/GLM-5.3-Flash) • [Terms](https://huggingface.co/zai-org/GLM-5.3-Flash/blob/main/LICENSE) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Hello!",
"model": "glm-5.3-flash"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "glm-5.3-flash",
"messages": [
{
"role": "user",
"content": "Hello!"
}
]
}'
```
The model returns its answer as the assistant message — an `output_text` item in Responses, the `message.content` field in Chat Completions — with `usage` token counts alongside it.
## gpt-5.4-nano
> OpenAI's GPT-5.4 nano is the most cost-efficient model in the GPT-5.4 family, served on ZeroGPU for high-volume and latency-sensitive workloads such as classification, extraction, routing, and sub-agent tasks. It supports function calling and structured outputs across a 400,000-token context window.
**References:** [Terms](https://openai.com/policies/services-agreement/) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Hello!",
"model": "gpt-5.4-nano"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gpt-5.4-nano",
"messages": [
{
"role": "user",
"content": "Hello!"
}
]
}'
```
The model returns its answer as the assistant message — an `output_text` item in Responses, the `message.content` field in Chat Completions — with `usage` token counts alongside it.
## gpt-5.6-luna
> OpenAI's GPT-5.6 Luna is the cost-optimized model of the GPT-5.6 family, served on ZeroGPU for cost-sensitive, high-volume workloads. It supports adjustable reasoning effort, function calling, and structured outputs across a 272,000-token context window.
**References:** [Terms](https://openai.com/policies/services-agreement/) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Hello!",
"model": "gpt-5.6-luna"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gpt-5.6-luna",
"messages": [
{
"role": "user",
"content": "Hello!"
}
]
}'
```
The model returns its answer as the assistant message — an `output_text` item in Responses, the `message.content` field in Chat Completions — with `usage` token counts alongside it.
## gpt-4.1-mini
> OpenAI's GPT-4.1 mini is the fast, cost-efficient model of the GPT-4.1 family, served on ZeroGPU for general text generation. It excels at instruction following and tool calling, supports function calling and structured outputs, and works across a 1,047,576-token (1M) context window with low latency.
**References:** [Terms](https://openai.com/policies/services-agreement/) • [Privacy](https://zerogpu.ai/privacy-policy)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Hello!",
"model": "gpt-4.1-mini"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "gpt-4.1-mini",
"messages": [
{
"role": "user",
"content": "Hello!"
}
]
}'
```
The model returns its answer as the assistant message — an `output_text` item in Responses, the `message.content` field in Chat Completions — with `usage` token counts alongside it.
## llama-3.1-8b-instruct-fast
> Meta's Llama 3.1 Instruct, tuned for fast, low-cost summarization at scale on the ZeroGPU edge network. Its 128K-token context window takes in entire documents, long transcripts, and full email or chat threads in a single pass. No chunking, no stitching partial summaries back together. Built for the high-volume summarization that runs around your core product: condensing long reports and transcripts, summarizing email and chat threads, and processing articles in bulk. When context length matters and you're summarizing on every request, this is the model that keeps it fast and affordable.
**References:** [Model docs](https://github.com/meta-llama/llama-models/tree/main/models/llama3_1) • [Terms](https://github.com/meta-llama/llama-models/blob/main/models/llama3_1/LICENSE) • [Privacy](https://github.com/meta-llama/llama-models/blob/main/models/llama3_1/USE_POLICY.md)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "The global semiconductor industry is undergoing one of its most significant structural shifts in decades, driven by a combination of geopolitical tensions, surging demand from artificial intelligence workloads, and a wave of government-backed industrial policy across the United States, Europe, and Asia. At the center of this transformation is a race to onshore chip manufacturing capacity that had, for thirty years, been quietly concentrated in Taiwan and South Korea. The United States CHIPS and Science Act, signed into law in 2022, allocated over $52 billion in subsidies to incentivize domestic semiconductor fabrication. Since then, companies including TSMC, Intel, Samsung, and Micron have announced or broken ground on new fabs in Arizona, Ohio, Texas, and Idaho. However, construction timelines have slipped, costs have ballooned, and a shortage of skilled workers has prompted some manufacturers to bring in engineers from overseas — a move that has drawn political scrutiny even as it addresses a genuine talent gap. Meanwhile, the explosion of AI model training and inference has fundamentally altered the demand profile for chips. Graphics processing units originally designed for gaming, particularly those made by NVIDIA, have become the primary compute substrate for large language models. NVIDIA's H100 and successor Blackwell-series GPUs now trade at significant premiums on secondary markets, with some hyperscalers reporting lead times of over a year for large cluster orders. This bottleneck has accelerated investment in custom silicon: Google's Tensor Processing Units, Amazon's Trainium and Inferentia chips, and Meta's MTIA accelerators are all attempts to reduce dependence on third-party GPU supply chains. On the geopolitical front, the United States has progressively tightened export controls on advanced chips and chip-making equipment destined for China, with the most recent rules targeting gate-all-around transistor technology and high-bandwidth memory. China, in response, has dramatically increased state investment in its domestic semiconductor ecosystem, with companies like SMIC and Huawei making incremental but closely watched progress at advanced nodes. Analysts remain divided on how quickly China can close the gap, with estimates ranging from five to fifteen years depending on assumptions about technology transfer, equipment access, and the pace of indigenous innovation. The equipment layer — often overlooked in public discourse — may prove to be the most consequential chokepoint. ASML, the Dutch company that holds a near-monopoly on extreme ultraviolet lithography machines, has become a focal point of both trade diplomacy and industrial strategy. Without EUV tools, fabricating chips below 7 nanometers at scale is effectively impossible, giving ASML and its supply chain extraordinary leverage in a world where nations are suddenly treating semiconductor access as a matter of national security.",
"model": "llama-3.1-8b-instruct-fast"
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "llama-3.1-8b-instruct-fast",
"messages": [
{
"role": "user",
"content": "The global semiconductor industry is undergoing one of its most significant structural shifts in decades, driven by a combination of geopolitical tensions, surging demand from artificial intelligence workloads, and a wave of government-backed industrial policy across the United States, Europe, and Asia. At the center of this transformation is a race to onshore chip manufacturing capacity that had, for thirty years, been quietly concentrated in Taiwan and South Korea. The United States CHIPS and Science Act, signed into law in 2022, allocated over $52 billion in subsidies to incentivize domestic semiconductor fabrication. Since then, companies including TSMC, Intel, Samsung, and Micron have announced or broken ground on new fabs in Arizona, Ohio, Texas, and Idaho. However, construction timelines have slipped, costs have ballooned, and a shortage of skilled workers has prompted some manufacturers to bring in engineers from overseas — a move that has drawn political scrutiny even as it addresses a genuine talent gap. Meanwhile, the explosion of AI model training and inference has fundamentally altered the demand profile for chips. Graphics processing units originally designed for gaming, particularly those made by NVIDIA, have become the primary compute substrate for large language models. NVIDIA's H100 and successor Blackwell-series GPUs now trade at significant premiums on secondary markets, with some hyperscalers reporting lead times of over a year for large cluster orders. This bottleneck has accelerated investment in custom silicon: Google's Tensor Processing Units, Amazon's Trainium and Inferentia chips, and Meta's MTIA accelerators are all attempts to reduce dependence on third-party GPU supply chains. On the geopolitical front, the United States has progressively tightened export controls on advanced chips and chip-making equipment destined for China, with the most recent rules targeting gate-all-around transistor technology and high-bandwidth memory. China, in response, has dramatically increased state investment in its domestic semiconductor ecosystem, with companies like SMIC and Huawei making incremental but closely watched progress at advanced nodes. Analysts remain divided on how quickly China can close the gap, with estimates ranging from five to fifteen years depending on assumptions about technology transfer, equipment access, and the pace of indigenous innovation. The equipment layer — often overlooked in public discourse — may prove to be the most consequential chokepoint. ASML, the Dutch company that holds a near-monopoly on extreme ultraviolet lithography machines, has become a focal point of both trade diplomacy and industrial strategy. Without EUV tools, fabricating chips below 7 nanometers at scale is effectively impossible, giving ASML and its supply chain extraordinary leverage in a world where nations are suddenly treating semiconductor access as a matter of national security."
}
]
}'
```
The summary is returned as `output[].content[].text` (Responses API) or `choices[].message.content` (Chat Completions).
```text Response theme={null}
The global semiconductor industry is undergoing a significant transformation driven by geopolitical tensions, surging demand from artificial intelligence workloads, and government-backed industrial policies. A race to onshore chip manufacturing capacity is underway, with the US, Europe, and Asia investing heavily in domestic fabrication, while companies like TSMC, Intel, and Samsung are building new fabs in the US. However, construction timelines have slipped, costs have increased, and a shortage of skilled workers has prompted some manufacturers to bring in overseas engineers. The demand for chips has also changed, with AI model training and inference driving a shortage of graphics processing units, particularly those made by NVIDIA. In response, companies like Google, Amazon, and Meta are investing in custom silicon to reduce dependence on third-party supply chains. The US has tightened export controls on advanced chips and equipment destined for China, which has responded with increased state investment in its domestic semiconductor ecosystem. The equipment layer, particularly ASML's near-monopoly on extreme ultraviolet lithography machines, may prove to be the most consequential chokepoint in the industry.
```
## llama-guard-4-12b
> Meta's Llama Guard 4 12B is a multimodal safety classification model for moderating text, images, and mixed text-image inputs. It evaluates both incoming prompts and generated responses, returning a safe or unsafe classification along with the policy categories a violation falls under. It handles multilingual text and multiple images in one call, which makes it a fit for chat moderation, prompt and response filtering, policy enforcement, and agent guardrails. Built on a dense 12B architecture derived from Llama 4 Scout, it is designed as a dedicated safety layer in front of a production model rather than as a general-purpose generator.
**References:** [Model docs](https://huggingface.co/meta-llama/Llama-Guard-4-12B) • [Terms](https://huggingface.co/meta-llama/Llama-Guard-4-12B) • [Privacy](https://huggingface.co/meta-llama/Llama-Guard-4-12B)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "llama-guard-4-12b",
"input": [
{
"type": "text",
"text": "I am so angry at this person that I want to hurt them. They are worthless and should be scared of what I might do next."
}
]
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "llama-guard-4-12b",
"messages": [
{
"role": "user",
"content": "I am so angry at this person that I want to hurt them. They are worthless and should be scared of what I might do next."
}
]
}'
```
```bash Moderations API theme={null}
curl https://api.zerogpu.ai/v1/moderations \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "llama-guard-4-12b",
"input": "I am so angry at this person that I want to hurt them. They are worthless and should be scared of what I might do next."
}'
```
On the Responses and Chat Completions endpoints the verdict comes back as the output text — `safe`, or `unsafe` followed by the violated policy categories. On `/v1/moderations` the response is OpenAI's moderations envelope, the same shape [`zlm-v1-moderation-edge`](/docs/moderation) returns.
## LFM2.5-1.2B-Instruct
> Liquid AI's LFM2.5-1.2B-Instruct is a hybrid architecture model purpose-built for on-device deployment, trained on 28 trillion tokens with multi-stage reinforcement learning. It delivers best-in-class instruction following and native tool-calling at the 1B scale — something very few models this size can do reliably. Its hybrid design gives it significantly faster inference with lower memory usage compared to transformer-only models of the same size. If you need a conversational model that can actually run on real devices without a GPU, this is it. Supports 8 languages including English, Chinese, Japanese, and Spanish.
**References:** [Model docs](https://docs.liquid.ai/deployment/on-device/android/ai-agent-usage-guide#text-models) • [Terms](https://www.liquid.ai/terms-conditions) • [Privacy](https://www.liquid.ai/lfm-license)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "I just completed a 5K run in 28 minutes. Give me a short motivational follow-up message.",
"model": "LFM2.5-1.2B-Instruct",
"instructions": "You are a friendly in-app assistant for a fitness app."
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "LFM2.5-1.2B-Instruct",
"messages": [
{
"role": "system",
"content": "You are a friendly in-app assistant for a fitness app."
},
{
"role": "user",
"content": "I just completed a 5K run in 28 minutes. Give me a short motivational follow-up message."
}
]
}'
```
```text Response theme={null}
That's an amazing accomplishment! Keep up the great work, each step brings you closer to your goals. You're stronger than you think!
Would you like tips to help you keep improving?
```
## LFM2.5-1.2B-Thinking
> Liquid AI's LFM2.5-1.2B-Thinking is a compact reasoning model that works through a problem step by step before it answers. Built by Liquid AI, it generates an explicit chain-of-thought trace so for multi-step math, planning, data extraction, and agentic tool-calling, you get verifiable intermediate reasoning, not just a final guess. At 1.2B parameters it fits under a gigabyte and runs fast on CPU at the edge, rivaling models several times its size on reasoning benchmarks. Reach for a frontier model when the task is knowledge-heavy or code-intensive, and keep this one as the planning brain that decides and orchestrates. When the task needs reasoning, this is the model.
**References:** [Model docs](https://docs.liquid.ai/deployment/on-device/android/ai-agent-usage-guide#text-models) • [Terms](https://www.liquid.ai/terms-conditions) • [Privacy](https://www.liquid.ai/lfm-license)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": "Our whole team got locked out of the dashboard this morning after the payment failed. We have a product demo with a customer in 2 hours and cannot log in. Card on file should be valid.",
"model": "LFM2.5-1.2B-Thinking",
"instructions": "You are a support triage assistant. Read the ticket, briefly reason about the signals, then assign one team (Billing, Technical, Account, General) and one priority (Low, Medium, High). Decide once and commit. End with a single line: TEAM | PRIORITY."
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "LFM2.5-1.2B-Thinking",
"messages": [
{
"role": "system",
"content": "You are a support triage assistant. Read the ticket, briefly reason about the signals, then assign one team (Billing, Technical, Account, General) and one priority (Low, Medium, High). Decide once and commit. End with a single line: TEAM | PRIORITY."
},
{
"role": "user",
"content": "Our whole team got locked out of the dashboard this morning after the payment failed. We have a product demo with a customer in 2 hours and cannot log in. Card on file should be valid."
}
]
}'
```
The model returns its answer alongside an explicit reasoning trace.
```text Response theme={null}
The capital of Japan is **Tokyo**.
**Reasoning:**
1. Japan's political, cultural, and economic center is located in Tokyo.
2. Historically, Tokyo has served as Japan's...
```
## qwen3.6-35b-a3b
> Alibaba's Qwen3.6-35B-A3B is a fast, open-weight multimodal model for applications that need to understand text, images, and video, served on ZeroGPU as an FP8 build. It suits visual question answering, document and screenshot analysis, video understanding, content extraction, agent workflows, and tool calling, and it supports structured output. Its Mixture-of-Experts architecture keeps inference efficient while it works through large amounts of multimodal content. When the input is images or video rather than text alone, this is the model.
**References:** [Model docs](https://huggingface.co/Qwen/Qwen3.6-35B-A3B) • [Terms](https://huggingface.co/Qwen/Qwen3.6-35B-A3B) • [Privacy](https://huggingface.co/Qwen/Qwen3.6-35B-A3B)
```bash Responses API theme={null}
curl https://api.zerogpu.ai/v1/responses \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"input": [
{
"role": "user",
"content": [
{
"type": "input_image",
"detail": "auto",
"image_url": "https://upload.wikimedia.org/wikipedia/commons/3/3a/Cat03.jpg"
},
{
"text": "What animal is this, and what is it doing?",
"type": "input_text"
}
]
}
],
"model": "qwen3.6-35b-a3b",
"temperature": 0.2,
"max_output_tokens": 512
}'
```
```bash Chat Completions theme={null}
curl https://api.zerogpu.ai/v1/chat/completions \
-H "content-type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-project-id: YOUR_PROJECT_ID" \
-d '{
"model": "qwen3.6-35b-a3b",
"messages": [
{
"role": "user",
"content": [
{
"type": "video_url",
"video_url": {
"url": "https://qianwen-res.oss-accelerate.aliyuncs.com/Qwen3.5/demo/video/N1cdUjctpG8.mp4"
}
},
{
"type": "image_url",
"image_url": {
"url": "https://upload.wikimedia.org/wikipedia/commons/3/3a/Cat03.jpg",
"detail": "auto"
}
},
{
"text": "Describe what happens in the video, then say whether the animal in the photo appears in it.",
"type": "text"
}
]
}
],
"max_tokens": 512,
"temperature": 0.2
}'
```
The model returns a text answer describing the images and video it was given.
# Introduction
Source: https://docs.zerogpu.ai/index
Run high-volume AI tasks on specialized small and nano language models across an edge-powered network - faster and cheaper, through one OpenAI-compatible API.
ZeroGPU is the compute efficiency layer for AI inference. It runs repeatable, high-volume AI tasks on specialized small and nano language models across an edge-powered network - so the same workloads run faster and cheaper than on centralized GPUs.
Send a request to one OpenAI-compatible endpoint; ZeroGPU picks the right small or nano model and runs it on the right compute. Frontier models for reasoning. ZeroGPU for repeatable execution - classification, extraction, moderation, summarization, routing - at the scale AI demands.
## Make your first call
Find your API key and project ID in the [ZeroGPU dashboard](https://platform.zerogpu.ai/dashboard).
```bash wrap theme={null}
curl --location 'https://api.zerogpu.ai/v1/responses' \
--header 'content-type: application/json' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'x-project-id: YOUR_PROJECT_ID' \
--data '{
"input": "Technology has quietly reshaped the rhythm of everyday life, weaving itself into routines so seamlessly that it often goes unnoticed. From the moment a smartphone alarm wakes someone in the morning to the final glance at a glowing screen before sleep, digital systems guide communication, navigation, work, and entertainment. This transformation did not happen overnight. It emerged through decades of incremental innovation, each new tool building upon the last, until the modern world became deeply interconnected.One of the most significant changes has been the speed at which information travels.",
"model": "zlm-v1-iab-classify-edge"
}'
```
Already using the OpenAI SDK? Point it at ZeroGPU:
```python wrap theme={null}
from openai import OpenAI
client = OpenAI(
base_url="https://api.zerogpu.ai/v1",
api_key="unused", # ZeroGPU authenticates via the headers below
default_headers={
"x-api-key": "YOUR_API_KEY",
"x-project-id": "YOUR_PROJECT_ID",
},
)
resp = client.responses.create(
model="zlm-v1-iab-classify-edge",
input="Technology has quietly reshaped the rhythm of everyday life, weaving itself into routines so seamlessly that it often goes unnoticed. From the moment a smartphone alarm wakes someone in the morning to the final glance at a glowing screen before sleep, digital systems guide communication, navigation, work, and entertainment. This transformation did not happen overnight. It emerged through decades of incremental innovation, each new tool building upon the last, until the modern world became deeply interconnected.One of the most significant changes has been the speed at which information travels.",
)
```
🎉 Either call returns the same classification result:
```json theme={null}
{
"audience": [
{ "name": "Technology & Computing", "score": 0.8194953318627214 },
{ "name": "Consumer Electronics", "score": 0.7730970665427267 },
{ "name": "IT and Internet Support", "score": 0.6476231908025892 }
],
"content": {
"iab_1_0": [
{ "name": "Technology & Computing", "score": 0.8130967783784443 },
{ "name": "Automotive", "score": 0.6588144281246334 }
],
"iab_2_2": [
{ "name": "Technology & Computing", "score": 0.8130967783784443 },
{ "name": "Wearable Technology", "score": 0.7080836335415118 },
{ "name": "Auto Infotainment Technologies", "score": 0.6588144281246334 }
]
}
}
```
## What you can run
## What you get
Specialized small and nano models on distributed compute. \~10x faster and 50%+ cheaper on production tasks.
`POST /v1/responses`; integrate with minimal code changes.
Token usage, latency, and volume per request, with project isolation for dev, staging, and production.
## How it works
One organization, multiple projects. Each gets its own API key and dashboard.
POST to `/v1/responses` with your key, project ID, and model. Response comes back as structured JSON.
Token usage, request volume, latency, error rates: all visible in the dashboard. Debug individual requests in Logs.
Workload analysis → Model selection → Edge orchestration. ZeroGPU classifies each task, picks the fastest viable model, and routes it to the right compute. See [How ZeroGPU works](/docs/how-zerogpu-works) for the full picture.
## Go deeper
Contribute compute from your idle devices to the ZeroGPU edge network and help power distributed AI inference.
# Claude Code Plugin
Source: https://docs.zerogpu.ai/integrations/claude-code-plugin
Route Claude Code subagents and slash commands through ZeroGPU's nano language models.
Claude Code is Anthropic's agentic coding tool that runs Claude directly in your terminal, with file editing, command execution, and a plugin system that extends sessions with custom slash commands and skills. Plugins package skills that Claude can auto-invoke when a user request matches, or that users can call explicitly by name. The plugin marketplace lets teams share these extensions across projects.
ZeroGPU is an ultra-fast, compute-efficient inference provider for apps and agents. We run purpose-built small and nano language models across an edge-powered network for the high-volume, purpose-specific tasks your app or agent runs constantly. Plug in our OpenAI-compatible API and you're live - zero GPU infrastructure, serverless, auto-scaling by default.
## Overview
This guide walks through installing the `zerogpu-router` plugin, which exposes every ZeroGPU CLI command as a Claude Code skill. You'll install the CLI, authenticate, load the plugin from its marketplace, and try both auto-invoked and manually-invoked skills. By the end you'll be able to offload cheap, well-defined NLP tasks (classification, entity and PII extraction, short chat) from Claude to ZeroGPU's edge-optimized models without leaving your terminal session.
## Video walkthrough
## Quickstart
### Prerequisites
* Node.js 20 or newer.
* [Claude Code](https://docs.claude.com/en/docs/claude-code) installed: `npm install -g @anthropic-ai/claude-code`.
* A ZeroGPU [API key](https://platform.zerogpu.ai/dashboard) and Project ID.
* A model ID from the [model catalog](/docs/model-catalog) if you plan to call models by name.
### Get your ZeroGPU API key
1. Sign in to the [ZeroGPU dashboard](https://platform.zerogpu.ai/dashboard).
2. Open **API Keys** and click **Create key**.
3. Copy the key (starts with `zgpu-api-`) and grab your Project ID (UUID) from the project settings page.
### Install the ZeroGPU CLI
```bash theme={null}
npm install -g zerogpu-cli
zerogpu --version
```
Then authenticate so every skill call works without re-prompting:
```bash theme={null}
zerogpu login
```
You'll be prompted for your API key and Project ID. For CI or non-interactive setups, pass them as flags:
```bash theme={null}
zerogpu login \
--api-key zgpu-api-XXXXXXXXXXXXXXXXXX \
--project-id 4ed3e5bb-c2ed-4d4a-8a66-2b161a27fd1a
```
### Your first request
Start a Claude Code session by running `claude` in your terminal, then add the marketplace and install the plugin:
```text theme={null}
/plugin marketplace add zerogpu/zerogpu-router
/plugin install zerogpu-router@zerogpu
/reload-plugins
```
Confirm it's loaded with `/plugin`. You should see `zerogpu-router - enabled`. Now try a skill:
```text theme={null}
/zerogpu-router:redact-pii "Email John Smith at john@acme.com about invoice 12345."
```
You'll get back: `Email [PERSON] at [EMAIL] about invoice 12345.`
## Usage
Every inference skill auto-invokes when Claude detects a matching request, or you can call any skill explicitly with `/zerogpu-router: `. Two skills (`signin` and `status`) are manual-only. This section walks through every skill in the plugin: what it does, which ZeroGPU model it routes to, the full argument surface, and the shape of the response you'll get back.
#### How auto-invocation works
The plugin ships each skill with a description that Claude reads when deciding whether to invoke it for a given user message. You don't have to remember slash command names: just describe the task. Claude picks based on intent words like "redact", "scrub", "classify by", "extract", or "tag this as", and on the structure of the data you supply (a label list implies zero-shot; a JSON schema with category axes implies structured classification).
Three common auto-invoked patterns:
```text theme={null}
Redact PII from this support ticket before I paste it into our public tracker:
"Hi team, this is Sarah Chen (sarah.chen@northwind-labs.com, +1 415-555-0182).
Our prod database started throwing connection timeouts around 2:14 AM PT last
night. The on-call engineer Marcus Rivera restarted pgbouncer but the issue
came back. Billing should go to our CFO Priya Patel at
priya.patel@northwind-labs.com, billing address 1455 Market St, Suite 600,
San Francisco, CA 94103."
```
Claude routes to `redact-pii`. Names, emails, phone numbers, and street addresses come back replaced by uppercase label placeholders like `[PERSON]`, `[EMAIL]`, `[PHONE_NUMBER]`, and `[ADDRESS]`. The raw PII never enters Claude's context window, which is the point: you can paste the masked output into a public tracker or log without leaking customer data. Project-specific identifiers (internal hostnames, IPs, contract numbers, card last-fours) aren't in the model's label set; strip those yourself, or use `extract-entities` with custom labels.
```text theme={null}
Pull all the email addresses and phone numbers out of this:
"Reach Maria at maria@acme.io or 415-555-0188"
```
Claude routes to `extract-pii`, which returns structured JSON grouped by category instead of an in-line mask.
```text theme={null}
Classify this support ticket by sentiment and topic:
"Support replied quickly but the fix didn't work"
```
Claude routes to `classify-structured` and synthesizes a schema with `sentiment` and `topic` axes before calling the skill.
If you ever want a specific skill instead of letting Claude choose, invoke it explicitly with the `/zerogpu-router:` syntax shown below.
#### `/zerogpu-router:signin`
Sign in to ZeroGPU and persist your credentials so every subsequent skill call works without re-prompting. Manual only; not auto-invoked by Claude.
**Wraps** `zerogpu login`.
**Synopsis**
```text theme={null}
/zerogpu-router:signin [--api-key ] [--project-id ]
```
| Flag | Required | Description |
| - | - | - |
| `--api-key ` | optional | API key. Must start with `zgpu-api-`. If omitted, you'll be prompted (masked). |
| `--project-id ` | optional | Project ID (UUID v4). If omitted, you'll be prompted. |
On success the API key and Project ID are written to your config file, and `ZEROGPU_API_KEY` is added to your shell profile so other tools can pick it up.
#### `/zerogpu-router:status`
Show your current ZeroGPU sign-in status and the masked API key. Manual only.
**Wraps** `zerogpu status`. Exit code is `0` when signed in, `1` when not. Use this in scripts that need a hard fail before running any inference skill.
#### `/zerogpu-router:chat`
Short, single-turn chat reply for things that don't need Claude-level reasoning or prior conversation context. Use this when you'd otherwise burn Claude tokens on a one-liner.
* **Model:** `LFM2.5-1.2B-Instruct`
* **Wraps:** `zerogpu chat`
* **When Claude auto-invokes:** quick factual answers, one-liners, basic rephrasings where you've signalled "use a small model."
**Synopsis**
```text theme={null}
/zerogpu-router:chat [-i ]
```
| Name | Required | Description |
| - | - | - |
| `text` | yes | The user message / prompt (quoted). |
| `-i`, `--instructions ` | optional | System instructions to steer behavior. |
**Example**
```text theme={null}
/zerogpu-router:chat "Explain WebSockets in two sentences." -i "You are a concise technical writer."
```
The skill returns raw assistant text (or pretty-printed JSON if the model returned a structured object).
#### `/zerogpu-router:chat-thinking`
Same shape as `chat`, but the model returns its reasoning trace alongside the answer.
* **Model:** `LFM2.5-1.2B-Thinking`
* **Wraps:** `zerogpu chat_thinking`
* **When Claude auto-invokes:** short logic / math / word-problem questions where step-by-step reasoning is useful or explicitly requested.
**Example**
```text theme={null}
/zerogpu-router:chat-thinking "If a train leaves at 3 PM going 60 mph, when does it cover 150 miles?"
```
#### `/zerogpu-router:summarize`
Condense a longer passage into a short summary. Use this when you need the gist of a report, ticket thread, transcript, or document without spending Claude tokens on the read.
* **Model:** `llama-3.1-8b-instruct-fast`
* **Wraps:** `zerogpu summarize`
* **When Claude auto-invokes:** "summarize this", "give me the gist", "TL;DR this passage", "condense this into a few sentences."
**Synopsis**
```text theme={null}
/zerogpu-router:summarize
```
**Example**
```text theme={null}
/zerogpu-router:summarize "The board met Thursday to review Q3 results. Revenue rose 18% \
year-over-year to $42M, driven mainly by enterprise renewals and a strong launch in the EU \
market. Operating margin slipped to 11% from 14% as headcount grew 30% ahead of the new \
data-center buildout. The CFO flagged rising cloud costs as the top risk for Q4 and proposed \
a hiring freeze on non-engineering roles until margins recover. The board approved the freeze \
and asked for a revised 2025 budget by mid-December."
```
**Illustrative output**
```text theme={null}
Q3 revenue grew 18% YoY to $42M on enterprise renewals and EU growth, but operating margin
fell to 11% due to a 30% headcount increase for the data-center buildout. Citing cloud costs
as the main Q4 risk, the board approved a hiring freeze on non-engineering roles and requested
a revised 2025 budget by mid-December.
```
#### `/zerogpu-router:classify-iab`
Classify text against the **IAB content / audience taxonomy** (standard ad-tech category labels).
* **Model:** `zlm-v1-iab-classify-edge`
* **Wraps:** `zerogpu classify_iab`
* **When Claude auto-invokes:** "what IAB category is this?", "tag this article for ad targeting", "give me the topic taxonomy."
**Example**
```text theme={null}
/zerogpu-router:classify-iab "The Lakers signed a new point guard ahead of the playoffs."
```
**Illustrative output**
```json theme={null}
{
"categories": [
{ "id": "IAB17-44", "name": "Basketball", "confidence": 0.97 }
]
}
```
#### `/zerogpu-router:classify-iab-enriched`
Enriched IAB classification that returns audience categories **plus** topics, keywords, and inferred user intent.
* **Model:** `zlm-v2-iab-classify-edge-enriched`
* **Wraps:** `zerogpu classify_iab_enriched`
* **When Claude auto-invokes:** "give me topics, keywords, and intent", any request asking for richer ad/audience signals than plain IAB labels.
**Example**
```text theme={null}
/zerogpu-router:classify-iab-enriched "Compare the Tesla Model Y and the Hyundai Ioniq 5 for a family of four."
```
**Illustrative output**
```json theme={null}
{
"categories": [{ "id": "IAB2-1", "name": "Auto Buyers", "confidence": 0.92 }],
"topics": ["electric vehicles", "family cars"],
"keywords": ["Tesla Model Y", "Hyundai Ioniq 5"],
"intent": "comparison-shopping"
}
```
#### `/zerogpu-router:classify-zero-shot`
Zero-shot classification against an arbitrary list of candidate labels you supply at call time. The model picks the single best fit and returns scores for all candidates.
* **Model:** `deberta-v3-small`
* **Wraps:** `zerogpu classify_zero_shot`
* **When Claude auto-invokes:** "is this positive, negative, or neutral?", "tag this as bug, feature, or question."
**Synopsis**
```text theme={null}
/zerogpu-router:classify-zero-shot (-l