How to Use Webhooks
Receive an HTTP callback when a task finishes, instead of polling for it.
Overview
Pass a callback URL when you submit a task and Get3W will POST the result to it once the task reaches a terminal state (completed or failed). This is the better choice for long-running jobs like video generation, where polling wastes requests.
Delivery runs in a background thread on the worker, so it never blocks task execution.
Setup
The callback URL goes in the webhook query parameter, not the request body:
curl -X POST "https://api.get3w.com/v1/google/nano-banana-pro/text-to-image?webhook=https://your-server.com/callback" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A cat in space",
"aspect_ratio": "16:9"
}'Remember to URL-encode the callback URL if it contains query parameters of its own.
The submit call returns immediately:
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "created",
"estimated_duration": 52
}Webhook Payload
When the task finishes, Get3W POSTs this JSON body to your URL:
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"model": "google/nano-banana-pro/text-to-image",
"status": "completed",
"code": 0,
"created_at": "2026-03-28T07:50:42",
"input": {
"prompt": "A cat in space",
"aspect_ratio": "16:9"
},
"outputs": ["https://storage.example.com/output.png"],
"error": null
}| Field | Type | Description |
|---|---|---|
id | string | Task ID, same as the submit response |
model | string | Model slug |
status | string | completed or failed |
code | int | 0 on success; see Error Codes on failure |
created_at | string | When the task was created |
input | object | The parameters you submitted |
outputs | string[] | Output URLs; empty when the task failed |
error | string | Error message; null when the task succeeded |
On failure the shape is the same, with outputs empty and error populated:
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"model": "google/nano-banana-pro/text-to-image",
"status": "failed",
"code": 1200,
"created_at": "2026-03-28T07:50:42",
"input": { "prompt": "..." },
"outputs": [],
"error": "Content moderation: prompt contains prohibited content"
}Because every delivery carries the same keys, you can branch on status without checking for missing fields.
Handling Webhooks
Python (Flask)
from flask import Flask, request
app = Flask(__name__)
@app.route("/callback", methods=["POST"])
def handle_webhook():
data = request.json
if data["status"] == "completed":
print(f"Task {data['id']} completed: {data['outputs']}")
elif data["status"] == "failed":
print(f"Task {data['id']} failed ({data['code']}): {data['error']}")
return "", 200Node.js (Express)
const express = require("express");
const app = express();
app.use(express.json());
app.post("/callback", (req, res) => {
const { id, status, outputs, code, error } = req.body;
if (status === "completed") {
console.log(`Task ${id} completed:`, outputs);
} else if (status === "failed") {
console.log(`Task ${id} failed (${code}):`, error);
}
res.sendStatus(200);
});
app.listen(3000);Requirements
- Your endpoint must be publicly reachable
- It must accept a POST with a JSON body
- It must return a 2xx within 30 seconds, or the delivery counts as failed
- HTTPS is recommended
For local development, expose your server with a tunneling tool such as ngrok.
Retry Policy
If your endpoint returns a non-2xx status or is unreachable, Get3W retries with exponential backoff:
| Attempt | Delay before attempt |
|---|---|
| 1st | Immediate |
| 2nd | 2 seconds |
| 3rd | 4 seconds |
After 3 failed attempts the delivery is abandoned. The result is not lost — you can still fetch it with GET /v1/requests/{request_id} for as long as the task record is retained.
TIP
Treat webhooks as a fast path, not the only path. A short reconciliation poll for tasks you never got a callback for makes the integration resilient to your own downtime.
Handling Duplicates
A retry can arrive after your server already processed the first delivery but failed to respond in time. Make your handler idempotent by keying on the task id and ignoring a delivery you have already seen.
Next Steps
- Webhook Mode — Full walkthrough with code samples
- Async Mode — Polling alternative
- Error Codes — Meaning of the
codefield