# Webhooks

Webhooks allow your application to receive real-time HTTP notifications when events happen in your Streampixel project — like a build being uploaded, approved, or rejected. Instead of polling for updates, Streampixel pushes event data directly to your endpoint.

**Common use cases:**

* Trigger deployments when a build is approved
* Send Slack or Discord alerts when a build is rejected
* Track build pipeline activity in your own monitoring systems
* Kick off automated testing&#x20;

### Setting Up Webhooks

1. Open your project in the Streampixel dashboard.
2. Go to **Project Settings**.
3. Enter your publicly accessible HTTPS endpoint in the **Webhook URL** field.
4. Use the **event checkboxes** to choose which events you want to receive (all are selected by default).
5. Click **Save**.
6. Click the **Test** button to verify your endpoint is working.

{% hint style="info" %}
Your endpoint must be reachable from the internet and able to accept HTTP POST requests.
{% endhint %}

### Webhook Events

Streampixel sends webhooks at each stage of the build pipeline:

| Event                | Description                                          |
| -------------------- | ---------------------------------------------------- |
| `build.uploaded`     | A new build file has been uploaded to the project.   |
| `build.downloading`  | The build file is being downloaded for processing.   |
| `build.extracting`   | The build file is being extracted and scanned.       |
| `build.saving`       | The build is being saved to the repository.          |
| `build.distributing` | The build is being distributed to streaming servers. |
| `build.approved`     | The build has been reviewed and approved.            |
| `build.rejected`     | The build has been reviewed and rejected.            |

Events fire in the order listed above, following the natural progression of the build pipeline. Not every build will trigger every event — for example, a rejected build will not fire `build.distributing`.

### Payload Reference

Every webhook is an **HTTP POST** request with a JSON body and `Content-Type: application/json` header.

#### Fields

| Field       | Type               | Description                                                                |
| ----------- | ------------------ | -------------------------------------------------------------------------- |
| `event`     | `string`           | The event type (e.g., `build.approved`). See the events table above.       |
| `projectId` | `string`           | The unique identifier of your Streampixel project.                         |
| `uploadId`  | `string` or `null` | The unique identifier of the uploaded build file.                          |
| `fileUrl`   | `string` or `null` | The URL of the build file, if available.                                   |
| `status`    | `string`           | The raw pipeline status (e.g., `Approved`, `Reject`, `Distribute`).        |
| `objection` | `string` or `null` | The reason for rejection. Only populated when `event` is `build.rejected`. |
| `timestamp` | `string`           | ISO 8601 timestamp of when the event occurred.                             |

#### Example: Build Approved

```json
{
  "event": "build.approved",
  "projectId": "664f1a2b3c4d5e6f7a8b9c0d",
  "uploadId": "665a2b3c4d5e6f7a8b9c0e1f",
  "fileUrl": "https://cdn.streampixel.io/builds/my-build.zip",
  "status": "Approved",
  "objection": null,
  "timestamp": "2026-03-29T14:30:00.000Z"
}
```

#### Example: Build Rejected

```json
{
  "event": "build.rejected",
  "projectId": "664f1a2b3c4d5e6f7a8b9c0d",
  "uploadId": "665a2b3c4d5e6f7a8b9c0e1f",
  "fileUrl": "https://cdn.streampixel.io/builds/my-build.zip",
  "status": "Reject",
  "objection": "Build contains unsupported file formats.",
  "timestamp": "2026-03-29T15:00:00.000Z"
}
```

#### Example: Build Uploaded

```json
{
  "event": "build.uploaded",
  "projectId": "664f1a2b3c4d5e6f7a8b9c0d",
  "uploadId": "665a2b3c4d5e6f7a8b9c0e1f",
  "fileUrl": null,
  "status": "pending",
  "objection": null,
  "timestamp": "2026-03-29T13:00:00.000Z"
}
```

### Testing Your Webhook

Click the **Test** button in Project Settings to send a test payload to your configured URL. The test payload looks like this:

```json
{
  "event": "webhook.test",
  "projectId": "test_project_id",
  "uploadId": "test_upload_id",
  "fileUrl": "https://example.com/test-build.zip",
  "status": "test",
  "objection": null,
  "timestamp": "2026-03-29T14:30:00.000Z"
}
```

* **Success** — The dashboard confirms the test was sent. Your endpoint responded with a 2xx status code.
* **Failure** — The dashboard shows an error. Check that your URL is correct, publicly accessible, and returns a 2xx response.

{% hint style="warning" %}
The `webhook.test` event is only sent when you click the Test button. It is never fired during normal build operations.
{% endhint %}

### Event Filtering

By default, all seven build events are enabled. You can customize which events you receive using the checkboxes in Project Settings.

**Examples:**

* **Only care about final outcomes?** Select just `build.approved` and `build.rejected`.
* **Want full pipeline visibility?** Keep all events selected.
* **Monitoring distribution?** Select `build.distributing` and `build.approved`.

If an event occurs that you have not subscribed to, no request is sent to your endpoint.

### Best Practices

{% hint style="danger" %}
Streampixel does **not** retry failed webhook deliveries. If your endpoint is unreachable or returns a non-2xx status, the event notification is lost. Make sure your endpoint has high availability.
{% endhint %}

* **Respond quickly** — Return a `200 OK` as fast as possible. Streampixel waits up to **10 seconds** before timing out. Move heavy processing to a background job.
* **Use HTTPS** — Always use an HTTPS URL to ensure the payload is encrypted in transit.
* **Be idempotent** — In rare cases the same event may arrive more than once. Use the `uploadId` + `event` combination to detect and skip duplicates.
* **Log everything** — Log all incoming payloads for debugging. This makes it much easier to troubleshoot integration issues.
* **Validate the project** — Check that the `projectId` in the payload matches your expected project.
* **Monitor uptime** — Since there are no retries, any downtime means missed events. Set up uptime monitoring for your webhook endpoint.

### Example: Receiving Webhooks

{% tabs %}
{% tab title="Node.js (Express)" %}

```javascript
const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhooks/streampixel', (req, res) => {
  const { event, projectId, uploadId, objection } = req.body;

  console.log(`Received event: ${event} for project: ${projectId}`);

  switch (event) {
    case 'build.approved':
      console.log(`Build ${uploadId} approved. Triggering deployment...`);
      // Start your deployment pipeline
      break;

    case 'build.rejected':
      console.log(`Build ${uploadId} rejected. Reason: ${objection}`);
      // Notify your team
      break;

    case 'webhook.test':
      console.log('Test webhook received successfully!');
      break;

    default:
      console.log(`Event: ${event}`);
  }

  // Always respond with 200 quickly
  res.status(200).json({ received: true });
});

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});
```

{% endtab %}

{% tab title="Python (Flask)" %}

```python
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/webhooks/streampixel', methods=['POST'])
def handle_webhook():
    payload = request.get_json()

    event = payload.get('event')
    project_id = payload.get('projectId')
    upload_id = payload.get('uploadId')
    objection = payload.get('objection')

    print(f"Received event: {event} for project: {project_id}")

    if event == 'build.approved':
        print(f"Build {upload_id} approved. Triggering deployment...")
        # Start your deployment pipeline

    elif event == 'build.rejected':
        print(f"Build {upload_id} rejected. Reason: {objection}")
        # Notify your team

    elif event == 'webhook.test':
        print("Test webhook received successfully!")

    # Always respond with 200 quickly
    return jsonify({"received": True}), 200

if __name__ == '__main__':
    app.run(port=3000)
```

{% endtab %}
{% endtabs %}

### Troubleshooting

| Problem                   | Solution                                                                                                                                      |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Test webhook fails        | Ensure your URL is publicly accessible (not `localhost`). Use a tool like [ngrok](https://ngrok.com) for local development.                   |
| Not receiving webhooks    | Verify that the correct events are checked in Project Settings and that your webhook URL is saved.                                            |
| Receiving timeouts        | Your endpoint must respond within **10 seconds**. Move heavy processing to a background job.                                                  |
| Missing events            | Streampixel does not retry failed deliveries. If your server was down when the event fired, the notification is lost. Check your server logs. |
| Unexpected payload format | Ensure your server parses the `Content-Type: application/json` body correctly.                                                                |
| Duplicate events          | Use the `uploadId` + `event` combination as an idempotency key to skip duplicates.                                                            |

### Quick Reference

| Detail               | Value                                  |
| -------------------- | -------------------------------------- |
| **HTTP Method**      | `POST`                                 |
| **Content Type**     | `application/json`                     |
| **Timeout**          | 10 seconds                             |
| **Retries**          | None                                   |
| **Events Available** | 7 build pipeline events + 1 test event |
