Webhook Mode
Webhook mode returns a task ID immediately and sends the result to your callback URL when the task completes. No polling needed.
Prerequisites
Make sure you have an API key. See Get Started with API for setup instructions.
Step 1: Submit a Task with Webhook
Add ?webhook=YOUR_CALLBACK_URL to the submit endpoint:
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 sunset over mountains",
"aspect_ratio": "16:9",
"resolution": "1k",
"output_format": "png",
"channel": "stable"
}'import requests
response = requests.post(
"https://api.get3w.com/v1/google/nano-banana-pro/text-to-image",
params={"webhook": "https://your-server.com/callback"},
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"prompt": "A sunset over mountains",
"aspect_ratio": "16:9",
"resolution": "1k",
"output_format": "png",
"channel": "stable"
}
)
task = response.json()
print(task["id"]) # Task is running; result will be sent to your webhookconst apiKey = "YOUR_API_KEY";
const webhookUrl = encodeURIComponent("https://your-server.com/callback");
const response = await fetch(
`https://api.get3w.com/v1/google/nano-banana-pro/text-to-image?webhook=${webhookUrl}`,
{
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
prompt: "A sunset over mountains",
aspect_ratio: "16:9",
resolution: "1k",
output_format: "png",
channel: "stable"
})
}
);
const task = await response.json();
console.log(task.id); // Result will be sent to your webhookResponse (immediate):
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "created",
"estimated_duration": 52
}Step 2: Receive the Webhook
When the task completes (or fails), Get3W sends a POST request to your callback URL with the result:
{
"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 sunset over mountains",
"aspect_ratio": "16:9",
"resolution": "1k",
"output_format": "png",
"channel": "stable"
},
"outputs": [
"https://storage.example.com/output.png"
],
"error": null
}A failure carries the same keys — outputs is an empty array and error is populated:
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"model": "google/nano-banana-pro/text-to-image",
"status": "failed",
"code": 1400,
"created_at": "2026-03-28T07:50:42",
"input": { "prompt": "A sunset over mountains" },
"outputs": [],
"error": "Invalid input: prompt is required"
}Every delivery carries all eight keys, so you can branch on status without checking for missing fields.
Step 3: Handle the Webhook
Here's a minimal server that receives webhook callbacks:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/callback", methods=["POST"])
def webhook_handler():
data = request.json
if data["status"] == "completed":
print(f"Task {data['id']} completed!")
print(f"Outputs: {data['outputs']}")
elif data["status"] == "failed":
print(f"Task {data['id']} failed: {data['error']}")
return jsonify({"received": True}), 200
if __name__ == "__main__":
app.run(port=3000)const express = require("express");
const app = express();
app.use(express.json());
app.post("/callback", (req, res) => {
const data = req.body;
if (data.status === "completed") {
console.log(`Task ${data.id} completed!`);
console.log(`Outputs: ${data.outputs}`);
} else if (data.status === "failed") {
console.log(`Task ${data.id} failed: ${data.error}`);
}
res.json({ received: true });
});
app.listen(3000, () => console.log("Webhook server running on port 3000"));Webhook Payload Fields
| Field | Type | Description |
|---|---|---|
id | string | Task ID |
model | string | Model slug (e.g. google/nano-banana-pro/text-to-image) |
status | string | completed or failed |
code | int | 0 on success; see Error Codes on failure |
created_at | string | ISO 8601 timestamp |
input | object | The original request parameters |
outputs | string[] | Output URLs; empty array when the task failed |
error | string | Error message; null when the task succeeded |
Retry Policy
Get3W makes up to 3 delivery attempts if your server returns a non-2xx status or is unreachable: the first immediately, then after 2 seconds, then after 4 seconds. Each attempt times out after 30 seconds.
After the third attempt the delivery is abandoned. The result is not lost — fetch it with GET /v1/requests/{request_id} while the task record is retained. For that reason, treat webhooks as a fast path and keep a reconciliation poll for tasks you never got a callback for.
When to Use Webhook Mode
- Server-to-server integrations — No need to keep a connection open or run a polling loop
- Event-driven architectures — Trigger downstream workflows when a task completes
- High-throughput pipelines — Submit hundreds of tasks and process results as they arrive
TIP
Your webhook URL must be publicly accessible. For local development, use a tunneling tool like ngrok to expose your local server.
Next Steps
- Sync Mode — Simplest approach for quick tasks
- Async Mode — Poll for results instead of using webhooks