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

# Event Ingestion: Push Signals from External Tools

> Send events from GitHub, GitLab, Kubernetes, PagerDuty, Prometheus, Datadog, and generic webhooks into the Scrubbe signal pipeline via the ingestion API.

The ingestion API normalizes and deduplicates events from your existing monitoring and alerting tools, routing them into the Scrubbe signal pipeline for triage, correlation, and incident creation. All ingestion endpoints use `X-API-Key` authentication — JWT Bearer tokens are **not** accepted on these routes. Endpoints live under `/api/v1/ingestion`.

<Warning>
  Ingestion endpoints accept only `X-API-Key: <key>` authentication. Requests with `Authorization: Bearer` headers will be rejected with `401 Unauthorized`. Generate a key with the `ingestion:write` scope from the [API Keys](/api-reference/api-keys) page.
</Warning>

## How ingestion works

Each endpoint accepts a source-specific event payload, normalizes it to a canonical Scrubbe signal format, and deduplicates it against the existing signal stream. Duplicate events — identified by a combination of source, event type, and a fingerprint derived from the payload — are merged rather than creating redundant signals.

```http theme={null}
POST /api/v1/ingestion/<source>
X-API-Key: <key>
Content-Type: application/json

{ ...source-specific payload... }
```

A successful ingestion returns a signal ID you can use to track the event through the pipeline.

```json theme={null}
{
  "success": true,
  "message": "Event ingested successfully.",
  "data": {
    "signalId": "sig_01HX...",
    "deduplicated": false,
    "source": "prometheus"
  }
}
```

<ResponseField name="data.signalId" type="string">
  Unique ID assigned to this signal in the Scrubbe pipeline.
</ResponseField>

<ResponseField name="data.deduplicated" type="boolean">
  `true` if this event was merged into an existing signal rather than creating a new one.
</ResponseField>

<ResponseField name="data.source" type="string">
  The normalized source name recorded for the signal.
</ResponseField>

***

## POST /ingestion/github

Ingest a GitHub webhook event (push, pull request, deployment status, etc.).

<ParamField body="action" type="string" required>
  GitHub event action. Example: `"opened"`, `"completed"`.
</ParamField>

<ParamField body="repository" type="object" required>
  GitHub repository object from the webhook payload.
</ParamField>

<ParamField body="sender" type="object">
  GitHub user object representing the actor who triggered the event.
</ParamField>

<Tip>
  Point your GitHub webhook directly at this endpoint. Set the content type to `application/json` in your repository's webhook settings.
</Tip>

***

## POST /ingestion/gitlab

Ingest a GitLab webhook event (push, merge request, pipeline, etc.).

<ParamField body="object_kind" type="string" required>
  GitLab event kind. Example: `"push"`, `"merge_request"`, `"pipeline"`.
</ParamField>

<ParamField body="project" type="object" required>
  GitLab project object from the webhook payload.
</ParamField>

<ParamField body="user" type="object">
  GitLab user who triggered the event.
</ParamField>

***

## POST /ingestion/kubernetes

Ingest a Kubernetes event or alert (e.g., pod crash, OOMKilled, node not ready).

<ParamField body="type" type="string" required>
  Kubernetes event type. Example: `"Warning"`, `"Normal"`.
</ParamField>

<ParamField body="reason" type="string" required>
  Short reason string from the event. Example: `"OOMKilling"`, `"BackOff"`.
</ParamField>

<ParamField body="message" type="string" required>
  Human-readable event message.
</ParamField>

<ParamField body="involvedObject" type="object" required>
  The Kubernetes resource the event relates to (kind, name, namespace).
</ParamField>

<ParamField body="metadata" type="object">
  Standard Kubernetes object metadata (namespace, labels, creationTimestamp).
</ParamField>

***

## POST /ingestion/pagerduty

Ingest a PagerDuty webhook event (incident triggered, acknowledged, resolved, etc.).

<ParamField body="messages" type="object[]" required>
  Array of PagerDuty webhook message objects. Each message includes `event`, `incident`, and `log_entries`.
</ParamField>

<Note>
  PagerDuty webhook v3 payloads are supported. Configure the outbound webhook in your PagerDuty account to point to this endpoint.
</Note>

***

## POST /ingestion/prometheus

Ingest an Alertmanager webhook payload from Prometheus.

<ParamField body="receiver" type="string" required>
  Alertmanager receiver name.
</ParamField>

<ParamField body="status" type="string" required>
  Alert group status. One of: `"firing"`, `"resolved"`.
</ParamField>

<ParamField body="alerts" type="object[]" required>
  Array of Prometheus alert objects. Each alert contains `status`, `labels`, `annotations`, `startsAt`, and `endsAt`.
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url "https://your-api-domain.com/api/v1/ingestion/prometheus" \
    --header "Content-Type: application/json" \
    --header "X-API-Key: $API_KEY" \
    --data '{
      "receiver": "scrubbe-webhook",
      "status": "firing",
      "alerts": [
        {
          "status": "firing",
          "labels": {
            "alertname": "HighErrorRate",
            "severity": "critical",
            "service": "payment-api"
          },
          "annotations": {
            "summary": "Error rate above 5% for 5 minutes",
            "description": "The payment-api service is returning 5xx errors at 8.3%."
          },
          "startsAt": "2025-05-22T14:00:00Z",
          "endsAt": "0001-01-01T00:00:00Z"
        }
      ]
    }'
  ```

  ```python Python theme={null}
  import requests

  resp = requests.post(
      "https://your-api-domain.com/api/v1/ingestion/prometheus",
      headers={"X-API-Key": api_key},
      json={
          "receiver": "scrubbe-webhook",
          "status": "firing",
          "alerts": [{
              "status": "firing",
              "labels": {"alertname": "HighErrorRate", "severity": "critical"},
              "annotations": {"summary": "Error rate above 5%"},
              "startsAt": "2025-05-22T14:00:00Z",
              "endsAt": "0001-01-01T00:00:00Z"
          }]
      }
  )
  print(resp.json())
  ```
</CodeGroup>

***

## POST /ingestion/datadog

Ingest a Datadog webhook notification (monitor alert, recovery, etc.).

<ParamField body="id" type="string" required>
  Datadog monitor ID.
</ParamField>

<ParamField body="type" type="string" required>
  Datadog event type. Example: `"monitor alert"`, `"metric alert"`.
</ParamField>

<ParamField body="title" type="string" required>
  Monitor alert title.
</ParamField>

<ParamField body="body" type="string">
  Full monitor alert body text.
</ParamField>

<ParamField body="priority" type="string">
  Alert priority. One of: `"normal"`, `"low"`.
</ParamField>

<Note>
  Configure your Datadog webhook integration to point to this endpoint. Include the API key in the URL as a query parameter or set it as a custom header named `X-API-Key`.
</Note>

***

## POST /ingestion/webhook

Generic canonical webhook endpoint for tools not covered by a dedicated integration. Submit a normalized signal payload directly.

<ParamField body="source" type="string" required>
  Identifier for the originating tool or system. Example: `"custom-monitor"`, `"statuspage"`.
</ParamField>

<ParamField body="title" type="string" required>
  Short description of the event.
</ParamField>

<ParamField body="severity" type="string" required>
  Signal severity. One of: `"critical"`, `"high"`, `"medium"`, `"low"`, `"info"`.
</ParamField>

<ParamField body="status" type="string" required>
  Current state of the event. One of: `"firing"`, `"resolved"`.
</ParamField>

<ParamField body="message" type="string">
  Detailed description of the event.
</ParamField>

<ParamField body="metadata" type="object">
  Arbitrary key-value pairs for additional context. These are stored with the signal and surfaced in the Scrubbe UI.
</ParamField>

<ParamField body="timestamp" type="string">
  ISO 8601 timestamp of the original event. Defaults to the time of ingestion if omitted.
</ParamField>

```json theme={null}
{
  "source": "custom-monitor",
  "title": "Database connection pool exhausted",
  "severity": "critical",
  "status": "firing",
  "message": "All 100 connections in pool are in use. New queries are being queued.",
  "metadata": {
    "region": "us-east-1",
    "service": "orders-db"
  },
  "timestamp": "2025-05-22T15:30:00Z"
}
```
