Webhook
Introduction
To ensure timely updates and notifications, PiAPI offer webhook services integrated with our Unified API Schema.
When you create a task, you can specify a webhook endpoint. Our API service will then send an HTTP POST request to this URL whenever a task succeeds, fails, or has a status update.
Webhooks: Use Cases
Since input and output data (including any files) are automatically deleted after a set period, webhooks allow you to capture all metadata for completed tasks. This enables you to store the data in a database or save the output files to persistent storage before they are deleted.
Some tasks may take several minutes to complete. By using a webhook handler, you can send notifications—such as an email or a Slack message—when a task is completed.
Webhooks can capture the output of one long-running task and feed it into another model as input, enabling seamless automation across models.
:::highlight yellow 📌
Webhooks are only supported in the Unified API Schema. While the legacy version of the API remains fully functional, webhook capabilities are exclusive to the new unified API.
:::
Setting Up Webhooks
To use webhooks, include the webhook_config
field in the request body when creating a task. Specify the endpoint and secret.
//POST https://api.piapi.ai/api/v1/task
{
"model": "suno/v3-chorip",
"task_type": "lyrics",
"input": {},
"config": {
"webhook_config": {
"endpoint": "",
"secret": ""
}
}
}
Field | Description | Details |
---|---|---|
endpoint | The URL where the webhook will be sent | Ensure that the receiving server is accessible by Cloudflare workers. |
secret | Used to verify the request source | If a secret is provided, it will be included in the x-webhook-secret header. |
Receiving Webhooks
PiAPI sends an HTTP POST request to the specified URL when a task is created, updates its logs, generates output, or completes.
The request body is in JSON format and includes two key fields: timestamp
and data
.
The timestamp
helps in identifying duplicate notifications (such as in cases of retry), while the data
field mirrors the response from the unified fetch API.
{
"timestamp": 1723018391,
"data": {}
}
Field | Description | Details |
---|---|---|
timestamp | Unix timestamp | Useful for detecting duplicate notifications. |
data | Task data | Matches the structure from the unified fetch API. |
:::highlight purple 💡 | ||
The status field will have one of the following values: |
||
::: |
pending
: The request has been received but not yet started.processing
: The task is currently in progress.failed
: The task encountered an error.completed
: The task finished successfully.
The output
field is critical in webhook notifications as it reflects the current result or progress of the task, with content varying depending on the model and task type.
:::highlight orange 🚀
Here is an example of a webhook request for a Luma video generation task:
:::
{
"timestamp": 1724511853,
"data": {
"task_id": "58cb41b7-556d-46c0-b82e-1e116aa1a31a",
"model": "luma",
"task_type": "video_generation",
"status": "completed",
"config": {
"webhook_config": {
"endpoint": "https://webhook.site/1fbfe428-3e78-43be-8e98-1ede95750d25",
"secret": "123456"
}
},
"input": {
"aspect_ratio": "16:9",
"expand_prompt": true,
"image_end_url": "https://i.imgur.com/CSmEZud.png",
"image_url": "https://i.imgur.com/eJkSUnA.png",
"loop": false,
"user_prompt": ""
},
"output": {
"generation": {
"id": "ab9124ef-49d4-4da7-bf12-0c3891a3cca8",
"prompt": "",
"state": "completed",
"created_at": "2024-08-24T15:01:52.727Z",
"video": {
"url": "https://storage.cdn-luma.com/dream_machine/49995d70-d0f3-4b0d-afb0-ec034107e4e2/watermarked_video08fe0802a4e104f1a80fb6c6c658710ee.mp4",
"url_no_watermark": "https://img.midjourneyapi.xyz/ephemeral/db7420f9-8a24-48fd-ade5-ede803e835db.mp4",
"width": 1168,
"height": 864,
"thumbnail": ""
},
"like": null,
"estimate_wait_seconds": null
}
},
"meta": {
"created_at": "2024-08-24T23:01:12.3556324+08:00",
"started_at": "2024-08-24T23:01:36.7432691+08:00",
"ended_at": "2024-08-24T23:04:13.5301322+08:00",
"usage": {
"type": "luma_quota",
"frozen": 30,
"consume": 30
}
},
"detail": {
"account_id": 1,
"is_using_private_pool": false
},
"logs": [],
"error": {
"code": 0,
"message": ""
}
}
}
The status property will have one of the following values:
pending
: the system has received your request, but it has not yet started the prediction.processing
: the model is currently running.failed
: the prediction encountered an error during processing.completed
: the prediction completed successfully.
In webhook notifications, the
output
field within thedata
structure is particularly important as it represents the result (or latest progress) of the task. The content of the output field varies depending on the model and task type.- Suno
- Audio generation and audio stitching
{ "clips": [] // Same as the current fetch interface, returns a list of clips }
- Audio upload
{ "title": "", "clip_id": "", "duration": 10, "image_url": "" }
- Lyrics generation
{ "title": "", "text": "" }
- Audio generation and audio stitching
- Luma
- Video generation and extension
{ "generation": [] // Same as the current fetch interface }
- Video generation and extension
- Kling
- Video generation and extension
{ "task": {}, // Same as the current fetch interface "works": [] // Same as the current fetch interface }
- Video generation and extension
- Suno
Handling Webhook Deliveries
Your endpoint must return a successful status code (2xx) quickly to avoid timeouts before performing any complex logic.
To handle webhook requests, create an HTTP
or HTTPS
endpoint that accepts POST
requests with a JSON
payload. For local development, you can use HTTP
, but once publicly accessible, the endpoint must support HTTPS
.
- The endpoint should handle
POST
requests with the event object inJSON
format. - Always respond with a
2xx
status code before performing any extended logic.
Here's an example of a Next.js webhook handler:
// pages/api/piapi-webhook.js
export default async function handler(req, res) {
console.log("🪝 incoming webhook!", req.body.data.taskid);
const prediction = req.body;
await saveToMyDatabase(prediction);
await sendSlackNotification(prediction);
res.end();
}
Webhook Retries
If PiAPI does not receive a successful response (status 2xx
), or if it encounters a 4xx
or 5xx
error, it will retry the webhook after 5 seconds. Up to 3 attempts will be made for each notification.
Best Practices for Using Webhooks
- Use
HTTPS
for Security: Ensure your server uses HTTPS to protect data in transit, preventing unauthorized access. - Timestamp Verification: The
timestamp
in webhook requests is crucial for:- Preventing Replay Attacks: Compare the request’s
timestamp
with the current system time. If the difference is too large, reject the request. - Deduplication: Use the
timestamp
to avoid processing the same event multiple times.
- Preventing Replay Attacks: Compare the request’s
- Testing Webhooks: We recommend services like webhook.site to test and debug webhook requests before moving to production.