# API change event

EVENT `api-change`

> This reference is the **skmtc/api-change-webhooks** API on Hub. Star it to see each revision, and add a pipeline to get its changes. https://skmtc.dev/skmtc/apis/api-change-webhooks

A pipeline delivery. Delivery is at least once and in no fixed order.

## Request

- Method: `POST` to the HTTPS destination of the webhook action
- content-type: `application/cloudevents+json; charset=utf-8`
- `user-agent` (header, enum, required): Hub's webhook client; the `1` matches the `v1` of the event types. One of: `SKMTC-Hub-Webhooks/1`.
- `skmtc-signature` (header, string, required): `t=<unix seconds>,v1=<hex HMAC-SHA256>`. The HMAC key is the webhook's whole secret as UTF-8, `whsec_` prefix included; the signed content is `<t>.<raw body>`. Compute it from the raw body before parsing it, compare in constant time, and refuse a `t` more than five minutes from your clock. Each attempt signs again with a new `t` and the current secret. [Verify the signature](/docs/api-change-webhooks#verify-the-signature)

## Event data

Content type: `application/cloudevents+json; charset=utf-8`. Type: `object`.

One structured-mode CloudEvent 1.0: the pipeline delivery event.

- `specversion` (enum, required)
  - One of: `1.0`
- `id` (string, required): The same on every attempt of a delivery. Use it to find duplicates. A pipeline delivery that Run now starts again sends a new id.
- `source` (string, required): The Hub site that sent the event, e.g. `https://skmtc.dev`.
- `subject` (string, required): The API, as `{owner}/{slug}`.
- `time` (string, required): When Hub captured the event; for a pipeline delivery event, when the delivery started. This is not the publisher's time.
- `datacontenttype` (enum, required)
  - One of: `application/json`
- `type` (enum, required)
  - One of: `dev.skmtc.pipeline.delivery.v1`
- `data` (object, required): The data of a delivery event.
  - `deliveryId` (string, required): The id of the delivery on Hub, `pdv_` and 32 hex digits.
  - `pipeline` (object, required): The pipeline a delivery event is from.
    - `owner` (string, required): The handle of the account that owns the pipeline.
    - `name` (string, required)
    - `url` (string, required): The pipeline's page on Hub.
  - `api` (object, required): The API the event is about.
    - `id` (string, required)
    - `owner` (string, required)
    - `slug` (string, required)
    - `name` (string, required)
    - `url` (string, required): The API's page on Hub.
  - `revision` (object, required): The revision the delivery fired for.
    - `id` (string, required)
    - `contentHash` (string | null, required): The SHA-256 of the revision's document; `null` for a revision with no stored document.
    - `version` (string | null, required): The publisher's version label, when the revision has one. Not an order.
    - `publishedAt` (string | null, required): The publisher's timestamp, when it gave one.
    - `retrievedAt` (string, required): When Hub retrieved the revision.
    - `url` (string, required): The revision's page on Hub; the API's revisions page for a revision with no stored document.
  - `results` (array of ActionResult, required): One result for each action of the delivery, in the order they ran. The webhook action itself is not in the list.
    - `type` (enum, required): The type of an action.
      - One of: `generate`, `pullRequest`, `publish`, `webhook`
    - `outcome` (enum, required): What one action of a delivery came to. `skipped` - the action is set to skip. `notRun` - an earlier action failed, so the delivery stopped before it.
      - One of: `succeeded`, `failed`, `skipped`, `notRun`
    - `reasonCode` (string): A stable machine-readable code, when the action failed or did not run.
    - `detail` (string): What the action did or why it failed, e.g. the pull request URL or the published `name@version`.
    - `durationMs` (integer): How long the action took; absent for an action that did not run.

Example event:

```json
{
  "specversion": "1.0",
  "id": "string",
  "source": "https://example.com",
  "subject": "string",
  "time": "2026-10-30T12:00:00Z",
  "datacontenttype": "application/json",
  "type": "dev.skmtc.pipeline.delivery.v1",
  "data": {
    "deliveryId": "string",
    "pipeline": {
      "owner": "string",
      "name": "string",
      "url": "https://example.com"
    },
    "api": {
      "id": "string",
      "owner": "string",
      "slug": "string",
      "name": "string",
      "url": "https://example.com"
    },
    "revision": {
      "id": "string",
      "contentHash": "string",
      "version": "string",
      "publishedAt": "2026-10-30T12:00:00Z",
      "retrievedAt": "2026-10-30T12:00:00Z",
      "url": "https://example.com"
    },
    "results": [
      {
        "type": "generate",
        "outcome": "succeeded",
        "reasonCode": "string",
        "detail": "string",
        "durationMs": 0
      }
    ]
  }
}
```

## Response

### 2XX

Any 2xx: the delivery succeeded. Hub does not read the body.

### 307

Hub sends the same request to `location`, for not more than 3 redirects.

### 308

Hub sends the same request to `location`, for not more than 3 redirects.

### 3XX

Any other 3xx or 4xx: the delivery fails and Hub does not try again.

### 408

Hub tries again later with the same event `id`, for not more than 24 hours from the first attempt. Hub also tries again after a timeout of 10 seconds or a network error.

### 429

Hub tries again later with the same event `id`, for not more than 24 hours from the first attempt. Hub also tries again after a timeout of 10 seconds or a network error.

### 4XX

Any other 3xx or 4xx: the delivery fails and Hub does not try again.

### 5XX

Hub tries again later, as for 408 and 429.

## Changes

Webhooks have no change history: a webhook is keyed by its event name rather than a path and method, so no recorded change can name it.
