# Events

Every event type Kaabist emits, with the shape of its data.

Every event is delivered to your [webhook endpoints](https://docs.kaab.ist/guides/webhooks) and kept in the event log with the same envelope: `id` (`evt_…`), `type`, `created_at`, `org_id`, `mode` and `data`. See the [WebhookEvent object](https://docs.kaab.ist/reference/api/schemas/webhook-event) for the envelope and the [webhooks guide](https://docs.kaab.ist/guides/webhooks) for signatures and retries.

## job.queued

A job was accepted, re-queued after a worker lost it, resumed, or escalated to a heavier tier.

```json
{
  "type": "job.queued",
  "data": {
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": "acme-report@3"
  }
}
```

## job.blocked

A queued job is being held back because the organisation is out of credits; `reason` is `insufficient_credits`. Sent once per blocked stretch.

```json
{
  "type": "job.blocked",
  "data": {
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": "acme-report@3",
    "reason": "insufficient_credits"
  }
}
```

## job.started

A worker began running the job, sent on its first run only.

```json
{
  "type": "job.started",
  "data": {
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": "acme-report@3"
  }
}
```

## job.awaiting_input

The job paused at an `await_input` step and needs a value.

```json
{
  "type": "job.awaiting_input",
  "data": {
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": "acme-report@3"
  }
}
```

## job.needs_attention

The job paused and needs a decision; `reason` is the attention reason.

```json
{
  "type": "job.needs_attention",
  "data": {
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": "acme-report@3",
    "reason": "obstacle"
  }
}
```

## job.succeeded

The job finished and its result can be read.

```json
{
  "type": "job.succeeded",
  "data": {
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": null
  }
}
```

## job.failed

The job ended without a result; `reason` is the error code.

```json
{
  "type": "job.failed",
  "data": {
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": "acme-report@3",
    "reason": "blocked"
  }
}
```

## job.canceled

The job was canceled or aborted; `reason` is `canceled`.

```json
{
  "type": "job.canceled",
  "data": {
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": "acme-report@3",
    "reason": "canceled"
  }
}
```

## batch.completed

Every job of a batch has finished. `total` is the number of jobs in it.

```json
{
  "type": "batch.completed",
  "data": {
    "batch": "bat_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "total": 120
  }
}
```

## proposal.created

Kaabist proposed a fix for review, such as a relocated locator or a dismiss recipe. `kind` says which.

```json
{
  "type": "proposal.created",
  "data": {
    "proposal": "prp_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": "acme-report@3",
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "kind": "relocate"
  }
}
```

## proposal.decided

Somebody approved or rejected a proposal; `decision` says which.

```json
{
  "type": "proposal.decided",
  "data": {
    "proposal": "prp_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program": "acme-report@3",
    "job": null,
    "kind": "relocate",
    "decision": "approved"
  }
}
```

## schedule.run

A scheduled job ended with nothing to report: the result matched the previous run (`changed: false`), or the job did not succeed (`status`).

```json
{
  "type": "schedule.run",
  "data": {
    "schedule": "sch_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "status": "succeeded",
    "changed": false
  }
}
```

## schedule.changed

A scheduled run's watched fields differ from the previous run's. `changed_paths` lists up to 50 JSON Pointers and `diff_url` links to the diff.

```json
{
  "type": "schedule.changed",
  "data": {
    "schedule": "sch_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "changed_paths": [
      "/products/3/price",
      "/products/7/price"
    ]
  }
}
```

## schedule.paused

A schedule was paused, by a person or because the organisation ran out of credits; `reason` is `manual` or `credits`.

```json
{
  "type": "schedule.paused",
  "data": {
    "schedule": "sch_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "reason": "credits"
  }
}
```

## schedule.failing

Five runs of a schedule in a row did not succeed. The schedule keeps running; `failure_streak` counts the failures.

```json
{
  "type": "schedule.failing",
  "data": {
    "schedule": "sch_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "job": "job_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "failure_streak": 5
  }
}
```

## session.expired

A stored session stopped working and needs a new sign-in.

```json
{
  "type": "session.expired",
  "data": {
    "session": "ses_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "name": "acme"
  }
}
```

## program.drift_detected

A field of a published program version stopped filling, parsing or keeping its length, or the version's canary failed, before your next job notices. Sent once per version, field and `kind` while the finding stays open.

```json
{
  "type": "program.drift_detected",
  "data": {
    "program": "prg_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "program_version_id": "pv_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "field": "products[].price",
    "kind": "fill_rate_drop",
    "detail": "products[].price: fill rate 97% → 20% over the last 340 samples",
    "source": "statistics",
    "at": "2026-09-18T10:00:00.000Z"
  }
}
```

## credits.low

Allowance consumption crossed 80 % or 95 % this period; `level` says which. Sent once per level per period.

```json
{
  "type": "credits.low",
  "data": {
    "balance": 120,
    "level": 80
  }
}
```

## credits.exhausted

Nothing more can be consumed: schedules and canaries pause and new jobs are refused. Sent once, until credits arrive.

```json
{
  "type": "credits.exhausted",
  "data": {
    "balance": 0
  }
}
```

## credits.recharged

Credits arrived after the organisation ran out, or an auto-recharge completed. Paused schedules and canaries resume.

```json
{
  "type": "credits.recharged",
  "data": {
    "balance": 5000
  }
}
```

## byo.unhealthy

One of your own providers (proxy, model or captcha solver) started failing its health checks.

```json
{
  "type": "byo.unhealthy",
  "data": {
    "byo": "byo_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "kind": "proxy",
    "status": "failing",
    "detail": "probe answered 407 Proxy Authentication Required"
  }
}
```

## byo.recovered

A BYO provider that was `failing` or `degraded` passed two health checks in a row and is healthy again.

```json
{
  "type": "byo.recovered",
  "data": {
    "byo": "byo_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "kind": "proxy",
    "status": "healthy"
  }
}
```

## webhook.disabled

Kaabist switched one of your webhook endpoints off after its last 100 deliveries failed over at least a day. Fix the receiver and set the endpoint's `status` to `active` again.

```json
{
  "type": "webhook.disabled",
  "data": {
    "webhook": "whk_01j9zqk3q7m4n5p6r7s8t9v0wx",
    "reason": "auto",
    "failure_streak": 100,
    "failing_since": "2026-09-17T10:00:00.000Z"
  }
}
```

## ping

A test delivery you asked for. It goes only to that endpoint, and no event pattern selects it.

```json
{
  "type": "ping",
  "data": {
    "webhook": "whk_01j9zqk3q7m4n5p6r7s8t9v0wx"
  }
}
```
