Webhooks

Receive real-time HTTP callbacks when your render jobs complete or fail, instead of polling the job status endpoint.

How webhooks work

When you include a webhook_uri field in your movie script, PhantomFlow sends an HTTP POST request to that URL when the render job reaches a terminal state (completed or failed). This eliminates the need to poll the status endpoint and enables event-driven architectures.

Setting the webhook URL

Add the webhook_uri field at the top level of your movie JSON when submitting a render job:

{
  "width": 1920,
  "height": 1080,
  "webhook_uri": "https://your-server.com/webhooks/phantomflow",
  "scenes": [
    {
      "duration": 5,
      "elements": [
        {
          "type": "text",
          "text": "Hello World",
          "font_size": 48,
          "position": "center"
        }
      ]
    }
  ]
}

Webhook payload

When the job completes or fails, PhantomFlow sends a POST request with a JSON body to your webhook URL.

Completed Job Payload

{
  "job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "completed",
  "output_url": "https://cdn.phantomflow.dev/output/a1b2c3d4.mp4",
  "duration_seconds": 15.2,
  "credits_used": 16
}

Failed Job Payload

{
  "job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "failed",
  "error": {
    "code": "RENDER_FAILED",
    "message": "FFmpeg exited with code 1: Invalid video source URL"
  }
}

Payload Fields

ParameterTypeRequiredDescription
job_idstringYesThe job UUID that triggered the webhook.
statusstringYes"completed" or "failed".
output_urlstringNoDownload URL for the rendered video. Present only on completion.
duration_secondsnumberNoDuration of the rendered video. Present only on completion.
credits_usedintegerNoActual credits consumed. Present only on completion.
errorobjectNoError details with code and message. Present only on failure.

Retry behavior

If your webhook endpoint returns a non-2xx status code or the connection times out, PhantomFlow retries the delivery with exponential backoff:

AttemptDelay
1st retry30 seconds
2nd retry2 minutes
3rd retry10 minutes

After 3 failed attempts, the webhook delivery is abandoned. You can always retrieve the job result by polling GET /api/jobs/:job_id.

Verifying webhook authenticity

To verify that a webhook came from PhantomFlow and not a malicious third party, check the following:

  • Job ID validation: Look up the job_id in the payload against your own records. If you did not submit a job with that ID, reject the request.
  • HTTPS: Always use an HTTPS webhook URL to prevent payload interception.
  • IP allowlisting: If your infrastructure supports it, allowlist the IP ranges of the PhantomFlow worker servers.

Best Practices

  • Return a 200 status code quickly from your webhook handler. Process the payload asynchronously if needed.
  • Make your webhook handler idempotent. The same event may be delivered more than once due to retries.
  • Store the job_id and check for duplicates before processing to prevent double-processing.
  • Use the SSE progress endpoint (GET /api/jobs/:id/progress) for real-time progress updates during rendering, and webhooks for final completion notifications.