markdown · 5040 bytes Raw Blame History

Webhooks

The webhook delivery format (payloads, signing) and the webhook management API (CRUD over webhooks on a repo) are both shipped. The management endpoints are PAT-authenticated and share the canonical API conventions (JSON error envelopes, X-RateLimit-*, X-OAuth-Scopes, Link pagination).

Delivery format

See Webhooks (user docs) for the full delivery contract — headers, body framing, signature verification, retries, idempotency.

The user-docs page is intentionally the canonical place; an API consumer building a subscriber endpoint reads the same material.

Management API

All endpoints require an Authorization: Bearer <pat> header whose token carries the repo:write scope and the caller's role on the repo must reach settings:general (owner / write collaborator). Webhook secrets are write-only: they're set on create and rotated by passing a new secret on PATCH, but never returned in any response.

Method Path
GET /api/v1/repos/{owner}/{repo}/hooks
POST /api/v1/repos/{owner}/{repo}/hooks
GET /api/v1/repos/{owner}/{repo}/hooks/{id}
PATCH /api/v1/repos/{owner}/{repo}/hooks/{id}
DELETE /api/v1/repos/{owner}/{repo}/hooks/{id}
GET /api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries
GET /api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries/{did}
POST /api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries/{did}/redeliver

Create

POST /api/v1/repos/alice/demo/hooks
Authorization: Bearer <pat>
Content-Type: application/json

{
  "url":             "https://hooks.example.com/sink",
  "content_type":    "json",
  "events":          ["push", "pull_request"],
  "active":          true,
  "ssl_verification": true,
  "secret":          "shared-secret-or-omit-to-mint"
}

content_type is json (default) or form. Omitting secret mints a fresh one server-side. The server validates the URL against the SSRF allow-list (scheme + port + non-private resolution) so a 422 here means the target was rejected at create time — no silent delivery failures later.

A successful create returns the hook row at 201 Created and enqueues a synthetic ping delivery so the operator sees an immediate round-trip.

Patch

PATCH /api/v1/repos/alice/demo/hooks/42
Content-Type: application/json

{
  "url":    "https://hooks.example.com/v2",
  "events": ["push", "pull_request", "issues"],
  "active": false,
  "secret": "rotated-secret"
}

Fields are merged onto the current row: omit a field to keep its existing value. Passing secret rotates the HMAC key used for subsequent deliveries.

Deliveries

The deliveries list is paginated (default 30, max 100 per page) and emits standard Link: <...>; rel="next" … headers. The single-delivery shape includes the captured request headers, request body, and response body so operators can replay a failed delivery from the recorded transcript.

POST .../deliveries/{did}/redeliver enqueues a fresh delivery copying the same payload + headers under a new id; the response body is {"id": <new_delivery_id>}.

Event types (canonical list)

The events shippable today, by X-Shithub-Event header:

  • push
  • pull_request (actions: opened, closed, merged, reopened, edited, ready_for_review, converted_to_draft, synchronize)
  • pull_request_review (actions: submitted, dismissed)
  • pull_request_review_comment
  • issues (actions: opened, closed, reopened, edited, assigned, unassigned, labeled, unlabeled)
  • issue_comment
  • check_run (actions: created, completed, rerequested)
  • check_suite (actions: requested, completed, rerequested)
  • workflow_run (actions: queued, running, completed)
  • workflow_job (actions: queued, running, completed, cancelled)
  • star
  • fork
  • repository (actions: created, deleted, archived, unarchived, renamed, transferred, publicized, privatized)
  • ping (test event you trigger manually)

Each event's payload is documented per-type in the webhook detail page's "Recent deliveries" inspector — that's currently the authoritative reference until per-event documentation lands here.

Actions payload safety

workflow_run and workflow_job payloads are structural snapshots: ids, run index, workflow path/name, head SHA/ref, event kind, status, conclusion, timestamps, job key/name, runner id, needs, timeout, and cancellation state. They intentionally do not include workflow event payloads, env, permissions, logs, runner JWTs, or secret values.

View source
1 # Webhooks
2
3 The webhook **delivery format** (payloads, signing) and the
4 webhook **management API** (CRUD over webhooks on a repo) are
5 both shipped. The management endpoints are PAT-authenticated and
6 share the canonical [API conventions](overview.md) (JSON error
7 envelopes, `X-RateLimit-*`, `X-OAuth-Scopes`, `Link`
8 pagination).
9
10 ## Delivery format
11
12 See [Webhooks (user docs)](../user/webhooks.md) for the full
13 delivery contract — headers, body framing, signature verification,
14 retries, idempotency.
15
16 The user-docs page is intentionally the canonical place; an API
17 consumer building a subscriber endpoint reads the same material.
18
19 ## Management API
20
21 All endpoints require an `Authorization: Bearer <pat>` header
22 whose token carries the `repo:write` scope and the caller's role
23 on the repo must reach **settings:general** (owner / write
24 collaborator). Webhook secrets are write-only: they're set on
25 create and rotated by passing a new `secret` on PATCH, but
26 **never** returned in any response.
27
28 | Method | Path |
29 |--------|----------------------------------------------------------------------------|
30 | GET | `/api/v1/repos/{owner}/{repo}/hooks` |
31 | POST | `/api/v1/repos/{owner}/{repo}/hooks` |
32 | GET | `/api/v1/repos/{owner}/{repo}/hooks/{id}` |
33 | PATCH | `/api/v1/repos/{owner}/{repo}/hooks/{id}` |
34 | DELETE | `/api/v1/repos/{owner}/{repo}/hooks/{id}` |
35 | GET | `/api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries` |
36 | GET | `/api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries/{did}` |
37 | POST | `/api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries/{did}/redeliver` |
38
39 ### Create
40
41 ```http
42 POST /api/v1/repos/alice/demo/hooks
43 Authorization: Bearer <pat>
44 Content-Type: application/json
45
46 {
47 "url": "https://hooks.example.com/sink",
48 "content_type": "json",
49 "events": ["push", "pull_request"],
50 "active": true,
51 "ssl_verification": true,
52 "secret": "shared-secret-or-omit-to-mint"
53 }
54 ```
55
56 `content_type` is `json` (default) or `form`. Omitting `secret`
57 mints a fresh one server-side. The server validates the URL
58 against the SSRF allow-list (scheme + port + non-private
59 resolution) so a 422 here means the target was rejected at
60 create time — no silent delivery failures later.
61
62 A successful create returns the hook row at `201 Created` and
63 enqueues a synthetic `ping` delivery so the operator sees an
64 immediate round-trip.
65
66 ### Patch
67
68 ```http
69 PATCH /api/v1/repos/alice/demo/hooks/42
70 Content-Type: application/json
71
72 {
73 "url": "https://hooks.example.com/v2",
74 "events": ["push", "pull_request", "issues"],
75 "active": false,
76 "secret": "rotated-secret"
77 }
78 ```
79
80 Fields are merged onto the current row: omit a field to keep its
81 existing value. Passing `secret` rotates the HMAC key used for
82 subsequent deliveries.
83
84 ### Deliveries
85
86 The deliveries list is paginated (default 30, max 100 per page)
87 and emits standard `Link: <...>; rel="next" …` headers. The
88 single-delivery shape includes the captured request headers,
89 request body, and response body so operators can replay a
90 failed delivery from the recorded transcript.
91
92 `POST .../deliveries/{did}/redeliver` enqueues a fresh delivery
93 copying the same payload + headers under a new id; the response
94 body is `{"id": <new_delivery_id>}`.
95
96 ## Event types (canonical list)
97
98 The events shippable today, by `X-Shithub-Event` header:
99
100 - `push`
101 - `pull_request` (actions: `opened`, `closed`, `merged`,
102 `reopened`, `edited`, `ready_for_review`, `converted_to_draft`,
103 `synchronize`)
104 - `pull_request_review` (actions: `submitted`, `dismissed`)
105 - `pull_request_review_comment`
106 - `issues` (actions: `opened`, `closed`, `reopened`, `edited`,
107 `assigned`, `unassigned`, `labeled`, `unlabeled`)
108 - `issue_comment`
109 - `check_run` (actions: `created`, `completed`, `rerequested`)
110 - `check_suite` (actions: `requested`, `completed`,
111 `rerequested`)
112 - `workflow_run` (actions: `queued`, `running`, `completed`)
113 - `workflow_job` (actions: `queued`, `running`, `completed`,
114 `cancelled`)
115 - `star`
116 - `fork`
117 - `repository` (actions: `created`, `deleted`, `archived`,
118 `unarchived`, `renamed`, `transferred`, `publicized`,
119 `privatized`)
120 - `ping` (test event you trigger manually)
121
122 Each event's payload is documented per-type in the webhook detail
123 page's "Recent deliveries" inspector — that's currently the
124 authoritative reference until per-event documentation lands here.
125
126 ### Actions payload safety
127
128 `workflow_run` and `workflow_job` payloads are structural snapshots:
129 ids, run index, workflow path/name, head SHA/ref, event kind, status,
130 conclusion, timestamps, job key/name, runner id, needs, timeout, and
131 cancellation state. They intentionally do **not** include workflow
132 event payloads, env, permissions, logs, runner JWTs, or secret values.