> ## Documentation Index
> Fetch the complete documentation index at: https://www.renderjuice.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Events

> Technical reference for Renderjuice webhook events, including payload schemas, delivery format, and signature verification.

Webhooks send signed payloads to your endpoints whenever specific lifecycle events occur. This reference documents the available event types, their payload structures, and how to verify webhook signatures.

<Tip>
  New to webhooks? Start with the [Webhooks guide](/docs/customizing-pipelines/webhooks) to understand use cases, best practices, and when webhooks are the right choice for your workflow.
</Tip>

## Setup

1. Sign in to the Renderjuice platform and make sure to be in the right workspace.
2. Navigate to **Profile & Settings → Webhooks**.
3. Add the HTTPS endpoint you'd like us to call.
4. Choose the event types you care about.

<Warning>
  Always return `200 OK` as quickly as possible—Renderjuice considers non-2xx responses or timeouts to be failures and will retry a limited number of times.
</Warning>

## Available events

Renderjuice currently files webhooks for the following events:

* **Job completed** (`onRenderComplete`) – Fired when a render job finishes successfully
* **Job failed** (`onRenderFail`) – Planned, not yet emitted

## Delivery format

* **Method**: `POST`
* **Body**: JSON
* **Headers**: `Content-Type: application/json`, plus signing headers below
* **Timeout**: 7s request timeout on our side; respond with `2xx` quickly and offload heavy work

## Payload schema (onRenderComplete)

<CodeGroup>
  ```ts webhook-payload.ts theme={null}
  type WebhookPayload = {
    event: "onRenderComplete";
    status: "completed";
    jobId: string;        // Render job ID (UUID)
    workspaceId: string;  // Workspace that owns the job
    completedAt: string;  // ISO 8601 timestamp
    outputs?: {
      frames: string[];   // Signed URLs for rendered frames (may be empty)
    };
  };
  ```
</CodeGroup>

## Example payload

<CodeGroup>
  ```json example-payload.json theme={null}
  {
    "event": "onRenderComplete",
    "status": "completed",
    "jobId": "465d7fed-dba7-4c49-8ca7-5bac5e4c4075",
    "workspaceId": "f61c980c-fbbe-472d-a047-d64c5b97c4ba",
    "completedAt": "2025-11-23T22:30:29.020Z",
    "outputs": {
      "frames": [
        "https://conduit.utxld.com/download/0001.jpg?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
      ]
    }
  }
  ```
</CodeGroup>

Notes:

* `outputs` is omitted when no frames are available.
* Frame URLs are signed and expire; fetch or cache what you need when the webhook arrives.

## Verifying webhook signatures

All webhook requests include cryptographic signatures so you can verify they originated from Renderjuice and haven't been tampered with.

You can view or regenerate your webhook secret in the dashboard under **Profile & Settings → Webhooks**.

### Signature headers

Each webhook request includes two headers:

* `X-Renderjuice-Signature` – HMAC-SHA256 signature of the request body
* `X-Renderjuice-Timestamp` – Unix timestamp (seconds since epoch) when the request was signed

### Verification process

1. Extract the signature and timestamp from the headers
2. Construct the signed payload: `{timestamp}.{requestBody}`
3. Compute HMAC-SHA256 using your webhook secret
4. Compare the computed signature with the header signature
5. Optionally verify the timestamp is recent (within 5 minutes) to prevent replay attacks

### Verification examples

<CodeGroup dropdown>
  ```javascript verify-signature.js theme={null}
  const crypto = require('crypto');

  function verifyWebhookSignature(secret, signature, timestamp, body) {
    const signedPayload = `${timestamp}.${body}`;
    const expectedSignature = crypto
      .createHmac('sha256', secret)
      .update(signedPayload)
      .digest('hex');
    
    return crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expectedSignature)
    );
  }

  // Usage
  const isValid = verifyWebhookSignature(
    process.env.WEBHOOK_SECRET,
    req.headers['x-renderjuice-signature'],
    req.headers['x-renderjuice-timestamp'],
    req.body
  );
  ```

  ```python verify_signature.py theme={null}
  import hmac
  import hashlib
  import time

  def verify_webhook_signature(secret, signature, timestamp, body):
      signed_payload = f"{timestamp}.{body}"
      expected_signature = hmac.new(
          secret.encode('utf-8'),
          signed_payload.encode('utf-8'),
          hashlib.sha256
      ).hexdigest()
      
      return hmac.compare_digest(signature, expected_signature)

  # Usage
  is_valid = verify_webhook_signature(
      os.environ['WEBHOOK_SECRET'],
      request.headers.get('X-Renderjuice-Signature'),
      request.headers.get('X-Renderjuice-Timestamp'),
      request.body
  )
  ```
</CodeGroup>

**Security best practices:**

* Although not required, it is highly recommended to verify signatures before processing webhook payloads
* Use constant-time comparison (e.g., `crypto.timingSafeEqual` in Node.js, `hmac.compare_digest` in Python) to prevent timing attacks
* Verify timestamps to prevent replay attacks (reject requests older than 5 minutes)
* Store webhook secrets securely (environment variables, secret managers)

## Retry behavior and error handling

* Non-2xx HTTP responses are considered failures
* Request timeouts are considered failures
* Renderjuice will retry failed deliveries a limited number of times
* After repeated failures, webhooks may be automatically disabled

### Best practices for webhook handlers

1. **Return 200 OK quickly** – Acknowledge receipt immediately, then process asynchronously
2. **Make handlers idempotent** – Use `eventId` or `domainIdempotencyKey` to deduplicate events
3. **Handle duplicate events** – The same event may be delivered multiple times due to retries
4. **Log all events** – Keep a record of received events for debugging and auditing
5. **Validate event structure** – Verify required fields are present before processing

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks Guide" icon="webhook" href="/docs/customizing-pipelines/webhooks">
    Learn use cases, patterns, and best practices
  </Card>

  <Card title="Combine with API" icon="code" href="/docs/customizing-pipelines/api">
    Use webhooks and API together for automation
  </Card>
</CardGroup>

If you need webhook integration support before these docs are finalized, reach out to [support@renderjuice.com](mailto:support@renderjuice.com)
