Pi can push job terminal-state events to your systems so automation platforms (n8n, agent runners, internal pipelines) can react without polling.
Endpoints
Method Path Description GET/api/v1/webhooksList all webhooks for your organization POST/api/v1/webhooksRegister a new webhook endpoint PATCH/api/v1/webhooks/:idEnable or disable a webhook
Register a webhook
POST to /api/v1/webhooks with the target URL and a shared secret:
Request fields
The HTTPS URL Pi will POST events to. Must use https.
Shared secret used to sign delivery payloads (HMAC SHA-256). Store this securely — Pi will not return it after creation.
Example
curl -X POST "https://api.example.com/api/v1/webhooks" \
-H "Authorization: Bearer pi_live_***" \
-H "Content-Type: application/json" \
-d '{"endpoint_url":"https://example.com/pi/webhooks","secret":"whsec_..."}'
List webhooks
Retrieve all webhooks registered for the authenticated organization:
curl -X GET "https://api.example.com/api/v1/webhooks" \
-H "Authorization: Bearer pi_live_***"
Enable or disable a webhook
PATCH /api/v1/webhooks/:id with is_active to toggle a webhook:
Request fields
Set to true to enable deliveries or false to pause them.
curl -X PATCH "https://api.example.com/api/v1/webhooks/<webhook_id>" \
-H "Authorization: Bearer pi_live_***" \
-H "Content-Type: application/json" \
-d '{"is_active":false}'
Event delivery
Event types
Pi delivers these events when async workers reach a terminal state:
Event Trigger job.completedJob finished successfully job.failedJob encountered an unrecoverable error
Every delivery includes:
Header Description X-Pi-EventEvent type (job.completed or job.failed) X-Pi-SignatureHMAC SHA-256 of the raw JSON body using your secret, formatted as sha256=<hex>
Payload shape
Unique event id (evt_pi_…). Use this to deduplicate deliveries.
Event type: job.completed or job.failed.
Unix timestamp in seconds.
Job type (e.g. avatar_generation).
URL to the result artifact, or null.
Error description for failed jobs, or null.
Job-specific output data.
{
"id" : "evt_pi_..." ,
"object" : "event" ,
"type" : "job.completed" ,
"created_at" : 1760000000 ,
"data" : {
"job" : {
"id" : "<job_id>" ,
"type" : "avatar_generation" ,
"status" : "completed" ,
"result_url" : null ,
"error_log" : null ,
"payload" : {
"phase" : "completed" ,
"image_url" : "https://...png" ,
"input" : {
"prompt" : "..." ,
"reference_image_count" : 0 ,
"client_reference_id" : "..." ,
"metadata" : { "workflow" : "..." }
}
}
}
}
}
Verifying signatures
Verify the X-Pi-Signature header before processing any delivery:
import crypto from "crypto" ;
export function verifyPiWebhookSignature ( params : {
secret : string ;
rawBody : string ;
signatureHeader : string | null ;
}) {
if ( ! params . signatureHeader ) return false ;
if ( ! params . signatureHeader . startsWith ( "sha256=" )) return false ;
const expected = crypto
. createHmac ( "sha256" , params . secret )
. update ( params . rawBody )
. digest ( "hex" );
const received = params . signatureHeader . slice ( "sha256=" . length );
return crypto . timingSafeEqual ( Buffer . from ( expected ), Buffer . from ( received ));
}
Always verify the signature before trusting the payload. Reject any delivery where verification fails.
Retry model
Pi retries delivery on non-2xx responses. Make your webhook handler idempotent by deduplicating on the evt_pi_* event id — the same event may be delivered more than once.
LiveKit webhook
Pi also exposes a signed LiveKit webhook endpoint for voice session events:
POST /api/v1/voice/webhooks/livekit
This endpoint verifies LiveKit’s native signature and is separate from the general webhook registry above. Configure its target URL in your LiveKit project settings pointing at your Pi deployment.