Async Tasks
Create, poll, list, and receive callbacks for EggAPI generation tasks
Every EggAPI generation model is asynchronous. POST /v1/generate creates the task immediately and returns 202 Accepted; workers process it in the background, and you read the result by polling or through a webhook.
Lifecycle
- Your app calls
POST /v1/generate; the API returns202 Acceptedwith the task ID. - A worker starts the generation with the upstream provider and polls it until it finishes.
- The worker saves the output, usage, and cost on the task.
- Your app reads the task with
GET /v1/tasks/{id}and gets it back ascompletedorfailed.
Task statuses:
| Status | Meaning |
|---|---|
pending | Task was created and queued. |
processing | Worker started provider execution or polling. |
completed | Output, cost, and usage have been recorded. |
failed | The task ended with an error message. |
Create a Task
curl -X POST https://api.eggapi.ai/v1/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-image-2/text-to-image",
"prompt": "A dashboard hero image with glass UI panels",
"aspect_ratio": "16:9",
"resolution": "1k",
"num_outputs": 1
}'Response:
{
"data": {
"id": "gen_3f2a9c1d-7b4",
"status": "pending",
"model": "openai/gpt-image-2/text-to-image",
"type": "image_generate",
"cost": "$0.00",
"created_at": "2026-05-08T10:30:00Z"
},
"error": null
}Poll a Task
curl https://api.eggapi.ai/v1/tasks/gen_3f2a9c1d-7b4 \ -H "Authorization: Bearer YOUR_API_KEY"
Completed image task:
{
"data": {
"id": "gen_3f2a9c1d-7b4",
"status": "completed",
"model": "openai/gpt-image-2/text-to-image",
"type": "image_generate",
"output": {
"url": "https://file.eggapi.ai/images/gen_3f2a9c1d-7b4/0.png",
"urls": ["https://file.eggapi.ai/images/gen_3f2a9c1d-7b4/0.png"]
},
"cost": "$0.0096",
"created_at": "2026-05-08T10:30:00Z",
"started_at": "2026-05-08T10:30:01Z",
"completed_at": "2026-05-08T10:30:10Z"
},
"error": null
}List Tasks
curl "https://api.eggapi.ai/v1/tasks?page=1&per_page=20" \ -H "Authorization: Bearer YOUR_API_KEY"
The list is under data.items, newest first, and pagination fields are under data.pagination (page, per_page, total, total_pages). per_page defaults to 20 and is at most 100.
Webhooks
Pass webhook_url when creating a task:
{
"model": "google/nano-banana-2/text-to-image",
"prompt": "A studio portrait with soft lighting",
"webhook_url": "https://example.com/eggapi/webhook"
}EggAPI posts JSON to your URL after completion or failure. All models use the same webhook envelope; different result types only change type and the optional fields under output. It sends these headers:
| Header | Description |
|---|---|
X-EggAPI-Timestamp | Unix timestamp used in the signature payload. |
X-EggAPI-Signature | sha256= plus HMAC-SHA256 of {timestamp}.{raw_body} using your webhook secret. |
Common fields:
| Field | Description |
|---|---|
event | task.completed or task.failed. |
task_id | EggAPI task ID, matching data.id from the polling API. |
status | completed or failed. |
model | Model ID from the original request. |
type | Task type: image_generate, image_edit, or video_generate. |
output | Present on success. Depending on the task type, it may include url, urls, duration_seconds, width, and height. |
error | Present on failure. |
cost | Task cost in USD as a decimal string. |
timestamp | Unix timestamp when the webhook payload was generated. |
Completed image payload:
{
"event": "task.completed",
"task_id": "gen_3f2a9c1d-7b4",
"status": "completed",
"model": "google/nano-banana-2/text-to-image",
"type": "image_generate",
"output": {
"url": "https://file.eggapi.ai/images/gen_3f2a9c1d-7b4/0.png",
"urls": ["https://file.eggapi.ai/images/gen_3f2a9c1d-7b4/0.png"],
"width": 1024,
"height": 576
},
"cost": "0.013500",
"timestamp": 1778217000
}Completed video payload:
{
"event": "task.completed",
"task_id": "gen_8c41e07a-2d9",
"status": "completed",
"model": "bytedance/seedance-2.5/text-to-video",
"type": "video_generate",
"output": {
"url": "https://file.eggapi.ai/videos/gen_8c41e07a-2d9/output.mp4",
"urls": ["https://file.eggapi.ai/videos/gen_8c41e07a-2d9/output.mp4"],
"duration_seconds": 5
},
"cost": "1.252275",
"timestamp": 1778217000
}Failed payload:
{
"event": "task.failed",
"task_id": "gen_3f2a9c1d-7b4",
"status": "failed",
"model": "google/nano-banana-2/text-to-image",
"type": "image_generate",
"error": "generation failed: upstream provider unavailable",
"cost": "0.000000",
"timestamp": 1778217000
}Webhook delivery uses a 30 second HTTP timeout. A delivery that fails or returns a non-2xx status is retried up to 5 attempts, starting 30 seconds later and doubling each time.
Verify the Signature
Find your webhook secret in the dashboard, then compare signatures over the raw request body before parsing it:
import crypto from "node:crypto";
function verifyEggApiWebhook(rawBody, timestamp, signature, secret) {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
return signature.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}Reject requests whose X-EggAPI-Timestamp is far from the current time to prevent replays.
Polling Helper
async function waitForTask(taskId, apiKey, timeoutMs = 300000) {
const start = Date.now();
while (Date.now() - start < timeoutMs) {
const response = await fetch(`https://api.eggapi.ai/v1/tasks/${taskId}`, {
headers: { "Authorization": `Bearer ${apiKey}` }
});
const { data, error } = await response.json();
if (error) throw new Error(error.message);
if (data.status === "completed") return data;
if (data.status === "failed") throw new Error(data.error || "Task failed");
await new Promise((resolve) => setTimeout(resolve, 3000));
}
throw new Error("Task timed out");
}