S38: docs — API reference (overview/auth/users/repos/issues/pulls/checks/webhooks/search/admin)
- SHA
1938837a704f323e466846e4b4be0ce3106d6bda- Parents
-
2f1f48e - Tree
1b4bed0
1938837
1938837a704f323e466846e4b4be0ce3106d6bda2f1f48e
1b4bed0| Status | File | + | - |
|---|---|---|---|
| A |
docs/public/api/admin.md
|
38 | 0 |
| A |
docs/public/api/auth.md
|
55 | 0 |
| A |
docs/public/api/checks.md
|
151 | 0 |
| A |
docs/public/api/issues.md
|
27 | 0 |
| A |
docs/public/api/overview.md
|
83 | 0 |
| A |
docs/public/api/pulls.md
|
23 | 0 |
| A |
docs/public/api/repos.md
|
31 | 0 |
| A |
docs/public/api/search.md
|
43 | 0 |
| A |
docs/public/api/users.md
|
89 | 0 |
| A |
docs/public/api/webhooks.md
|
57 | 0 |
docs/public/api/admin.mdadded@@ -0,0 +1,38 @@ | ||
| 1 | +# Admin (site-admin only) | |
| 2 | + | |
| 3 | +> **Planned.** The admin API is not exposed yet. Site-admin | |
| 4 | +> actions today are reachable through the `/admin/` web UI and | |
| 5 | +> the `shithubd admin` CLI subcommands. | |
| 6 | + | |
| 7 | +The site-admin surface is intentionally narrow: most operator | |
| 8 | +actions go through the CLI (`shithubd admin …`) where they're | |
| 9 | +auditable from journal logs. The planned API here exists for | |
| 10 | +automation that's already authenticated as a site admin (e.g., | |
| 11 | +an SSO/SCIM bridge). | |
| 12 | + | |
| 13 | +## Planned routes | |
| 14 | + | |
| 15 | +| Method | Path | Scope | Purpose | | |
| 16 | +|--------|------------------------------------------|----------------|----------------------------------| | |
| 17 | +| GET | `/api/v1/admin/users` | site-admin | List users (paginated). | | |
| 18 | +| GET | `/api/v1/admin/users/{id}` | site-admin | One user, with admin-only fields.| | |
| 19 | +| POST | `/api/v1/admin/users/{id}/suspend` | site-admin | Freeze the account. | | |
| 20 | +| POST | `/api/v1/admin/users/{id}/reinstate` | site-admin | Un-freeze. | | |
| 21 | +| POST | `/api/v1/admin/users/{id}/reset-password`| site-admin | Force a password reset email. | | |
| 22 | +| POST | `/api/v1/admin/users/{id}/site-admin` | site-admin | Grant or revoke site-admin bit. | | |
| 23 | + | |
| 24 | +## Authorization | |
| 25 | + | |
| 26 | +A regular PAT — even one held by a user who is a site admin — is | |
| 27 | +**not enough** by itself; the admin endpoints require both: | |
| 28 | + | |
| 29 | +- The token's owner has the `is_site_admin` flag set. | |
| 30 | +- The token has the `admin:site` scope (separate from `admin:org`). | |
| 31 | + | |
| 32 | +Both checks must pass; either alone returns 403. | |
| 33 | + | |
| 34 | +## Audit | |
| 35 | + | |
| 36 | +Every admin API call writes to the same `admin_audit_log` the | |
| 37 | +web admin UI uses. Each row carries the calling site admin's id, | |
| 38 | +the target id, the action, and the request IP. | |
docs/public/api/auth.mdadded@@ -0,0 +1,55 @@ | ||
| 1 | +# Authentication | |
| 2 | + | |
| 3 | +shithub's API is PAT-only. There is no OAuth / device-flow / JWT | |
| 4 | +issuance endpoint today. | |
| 5 | + | |
| 6 | +## Header | |
| 7 | + | |
| 8 | +``` | |
| 9 | +Authorization: Bearer shp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
| 10 | +``` | |
| 11 | + | |
| 12 | +`Authorization: token shp_…` is accepted as a synonym for tools | |
| 13 | +that hard-code GitHub's older syntax. | |
| 14 | + | |
| 15 | +## Token format | |
| 16 | + | |
| 17 | +PATs are 40 characters of base32 with the `shp_` prefix. They | |
| 18 | +match the regex: | |
| 19 | + | |
| 20 | +``` | |
| 21 | +shp_[A-Za-z0-9]{40} | |
| 22 | +``` | |
| 23 | + | |
| 24 | +Secret-scanning tools (GitHub's, GitGuardian's, etc.) recognize | |
| 25 | +this prefix. | |
| 26 | + | |
| 27 | +## Failure modes | |
| 28 | + | |
| 29 | +| Status | Body | Cause | | |
| 30 | +|-------:|-----------------------------------|------------------------------------------------------| | |
| 31 | +| 401 | `{"error":"unauthenticated"}` | Missing or malformed header. | | |
| 32 | +| 401 | `{"error":"invalid token"}` | Token doesn't exist, was revoked, or has expired. | | |
| 33 | +| 401 | `{"error":"account suspended"}` | The owning account has been suspended by an admin. | | |
| 34 | +| 403 | `{"error":"insufficient scope"}` | Token is valid but lacks the scope this route needs. | | |
| 35 | + | |
| 36 | +## Sessions | |
| 37 | + | |
| 38 | +The web UI uses session cookies, not PATs. Session cookies are | |
| 39 | +**not accepted** on `/api/v1/` — the API is PAT-only. This is a | |
| 40 | +deliberate choice: it keeps CSRF concerns off the API surface | |
| 41 | +and means every API caller is identified by an auditable token. | |
| 42 | + | |
| 43 | +## Creating a token programmatically | |
| 44 | + | |
| 45 | +There is no API for creating PATs; tokens are only created from | |
| 46 | +the web UI. This is intentional — the create-PAT surface is the | |
| 47 | +account's most security-sensitive non-password operation. | |
| 48 | + | |
| 49 | +## Future | |
| 50 | + | |
| 51 | +OAuth-style application authorizations (`client_id` + `client_ | |
| 52 | +secret`, `code` exchange, refresh tokens) are planned post-MVP. | |
| 53 | +For now, instruct human users to mint a PAT from their settings | |
| 54 | +and supply it to your app via the operator's secret-management | |
| 55 | +flow. | |
docs/public/api/checks.mdadded@@ -0,0 +1,151 @@ | ||
| 1 | +# Status checks | |
| 2 | + | |
| 3 | +External CI systems publish status into shithub via the check-runs | |
| 4 | +API. Branch-protection rules can require named contexts to pass | |
| 5 | +before a PR merges. | |
| 6 | + | |
| 7 | +## Concepts | |
| 8 | + | |
| 9 | +- A **check run** is one invocation: `(repo, head_sha, name)` | |
| 10 | + with a state and metadata. | |
| 11 | +- A **check suite** is the bag of check runs for one head SHA; | |
| 12 | + shithub computes it server-side. | |
| 13 | +- Branch protection's "required status checks" matches by **name** | |
| 14 | + on the head commit. | |
| 15 | + | |
| 16 | +## Create a check run | |
| 17 | + | |
| 18 | +``` | |
| 19 | +POST /api/v1/repos/{owner}/{repo}/check-runs | |
| 20 | +``` | |
| 21 | + | |
| 22 | +Required scope: `repo` (write). | |
| 23 | + | |
| 24 | +### Request body | |
| 25 | + | |
| 26 | +```json | |
| 27 | +{ | |
| 28 | + "name": "ci/lint", | |
| 29 | + "head_sha": "8c4e3f2a1b…", | |
| 30 | + "status": "in_progress", | |
| 31 | + "started_at": "2026-05-09T16:00:00Z", | |
| 32 | + "details_url": "https://ci.example/runs/12345", | |
| 33 | + "external_id": "12345", | |
| 34 | + "output": { | |
| 35 | + "title": "Lint", | |
| 36 | + "summary": "Running golangci-lint", | |
| 37 | + "text": "..." | |
| 38 | + } | |
| 39 | +} | |
| 40 | +``` | |
| 41 | + | |
| 42 | +| Field | Required | Notes | | |
| 43 | +|----------------|----------|------------------------------------------------------------| | |
| 44 | +| `name` | yes | The context name. Match this on branch-protection rules. | | |
| 45 | +| `head_sha` | yes | 40-char SHA-1 of the commit being checked. | | |
| 46 | +| `status` | no | `queued`, `in_progress`, `completed`. Default `queued`. | | |
| 47 | +| `conclusion` | iff `status=completed` | `success`, `failure`, `neutral`, `cancelled`, `timed_out`, `action_required`. | | |
| 48 | +| `started_at` | no | RFC 3339. | | |
| 49 | +| `completed_at` | iff `status=completed` | RFC 3339. | | |
| 50 | +| `details_url` | no | Where humans go to inspect the run. | | |
| 51 | +| `external_id` | no | Your system's identifier; echoed back on read. | | |
| 52 | +| `output` | no | `{title, summary, text}`. Summary is markdown. | | |
| 53 | + | |
| 54 | +### Response | |
| 55 | + | |
| 56 | +`201 Created` with the full check-run resource: | |
| 57 | + | |
| 58 | +```json | |
| 59 | +{ | |
| 60 | + "id": 9876, | |
| 61 | + "name": "ci/lint", | |
| 62 | + "head_sha": "8c4e3f2a1b…", | |
| 63 | + "status": "in_progress", | |
| 64 | + "conclusion": null, | |
| 65 | + "started_at": "2026-05-09T16:00:00Z", | |
| 66 | + "details_url": "https://ci.example/runs/12345", | |
| 67 | + "external_id": "12345", | |
| 68 | + "output": { "title": "Lint", "summary": "Running golangci-lint" } | |
| 69 | +} | |
| 70 | +``` | |
| 71 | + | |
| 72 | +## Update a check run | |
| 73 | + | |
| 74 | +``` | |
| 75 | +PATCH /api/v1/repos/{owner}/{repo}/check-runs/{id} | |
| 76 | +``` | |
| 77 | + | |
| 78 | +Required scope: `repo` (write). | |
| 79 | + | |
| 80 | +Same body shape as create; partial. Typical use: flip | |
| 81 | +`status: "completed"` with a `conclusion`. | |
| 82 | + | |
| 83 | +### Conclusion semantics | |
| 84 | + | |
| 85 | +| Conclusion | Effect on PR merge gate | | |
| 86 | +|-------------------|--------------------------------------------------------| | |
| 87 | +| `success` | Counts as passing. | | |
| 88 | +| `failure` | Blocks merge. | | |
| 89 | +| `neutral` | Doesn't block; doesn't count as passing either. | | |
| 90 | +| `cancelled` | Blocks merge. | | |
| 91 | +| `timed_out` | Blocks merge. | | |
| 92 | +| `action_required` | Blocks merge with a human-action signal. | | |
| 93 | + | |
| 94 | +## List check runs for a commit | |
| 95 | + | |
| 96 | +``` | |
| 97 | +GET /api/v1/repos/{owner}/{repo}/commits/{sha}/check-runs | |
| 98 | +``` | |
| 99 | + | |
| 100 | +Required scope: `repo:read`. | |
| 101 | + | |
| 102 | +Returns the most recent check run **per name** on this commit. | |
| 103 | +Older runs are still in the database (audit) but not in this | |
| 104 | +listing. | |
| 105 | + | |
| 106 | +```json | |
| 107 | +{ | |
| 108 | + "total_count": 2, | |
| 109 | + "check_runs": [ | |
| 110 | + {"id": 9876, "name": "ci/lint", "status": "completed", "conclusion": "success", ...}, | |
| 111 | + {"id": 9877, "name": "ci/test", "status": "in_progress", ...} | |
| 112 | + ] | |
| 113 | +} | |
| 114 | +``` | |
| 115 | + | |
| 116 | +## List check suites for a commit | |
| 117 | + | |
| 118 | +``` | |
| 119 | +GET /api/v1/repos/{owner}/{repo}/commits/{sha}/check-suites | |
| 120 | +``` | |
| 121 | + | |
| 122 | +Required scope: `repo:read`. | |
| 123 | + | |
| 124 | +Returns the rolled-up suite view per `head_sha`: | |
| 125 | + | |
| 126 | +```json | |
| 127 | +{ | |
| 128 | + "total_count": 1, | |
| 129 | + "check_suites": [ | |
| 130 | + { | |
| 131 | + "head_sha": "8c4e3f2a1b…", | |
| 132 | + "status": "in_progress", | |
| 133 | + "conclusion": null, | |
| 134 | + "checks_url": "/api/v1/repos/owner/repo/commits/8c4e3f2a1b…/check-runs" | |
| 135 | + } | |
| 136 | + ] | |
| 137 | +} | |
| 138 | +``` | |
| 139 | + | |
| 140 | +## Idempotency | |
| 141 | + | |
| 142 | +Check-run creates with the same `(repo, head_sha, name, | |
| 143 | +external_id)` are coalesced — re-publishing the same run from a | |
| 144 | +retried CI job is safe. | |
| 145 | + | |
| 146 | +## Permissions | |
| 147 | + | |
| 148 | +The PAT must belong to a user with **write access** to the repo. | |
| 149 | +Bot accounts representing CI runners are the typical pattern; | |
| 150 | +they're regular shithub accounts with PATs scoped to `repo` and | |
| 151 | +nothing else. | |
docs/public/api/issues.mdadded@@ -0,0 +1,27 @@ | ||
| 1 | +# Issues | |
| 2 | + | |
| 3 | +> **Planned.** Issues over the API are not yet shipped. The web | |
| 4 | +> UI is the only authoring surface today. | |
| 5 | + | |
| 6 | +## Planned routes | |
| 7 | + | |
| 8 | +| Method | Path | Scope | | |
| 9 | +|--------|--------------------------------------------------------|--------------| | |
| 10 | +| GET | `/api/v1/repos/{owner}/{repo}/issues` | `repo:read` | | |
| 11 | +| GET | `/api/v1/repos/{owner}/{repo}/issues/{number}` | `repo:read` | | |
| 12 | +| POST | `/api/v1/repos/{owner}/{repo}/issues` | `repo` | | |
| 13 | +| PATCH | `/api/v1/repos/{owner}/{repo}/issues/{number}` | `repo` | | |
| 14 | +| GET | `/api/v1/repos/{owner}/{repo}/issues/{number}/comments`| `repo:read` | | |
| 15 | +| POST | `/api/v1/repos/{owner}/{repo}/issues/{number}/comments`| `repo` | | |
| 16 | +| PATCH | `/api/v1/repos/{owner}/{repo}/issues/comments/{id}` | `repo` | | |
| 17 | +| DELETE | `/api/v1/repos/{owner}/{repo}/issues/comments/{id}` | `repo` | | |
| 18 | + | |
| 19 | +Filters on the list endpoint will mirror the web filters | |
| 20 | +(`state`, `author`, `assignee`, `label`, `milestone`, `since`, | |
| 21 | +`sort`, `direction`). | |
| 22 | + | |
| 23 | +## Markdown rendering | |
| 24 | + | |
| 25 | +Posted bodies are stored as raw markdown. Rendering happens at | |
| 26 | +read time, with the same `internal/markdown` pipeline the web UI | |
| 27 | +uses, so an API consumer sees the same HTML the browser would. | |
docs/public/api/overview.mdadded@@ -0,0 +1,83 @@ | ||
| 1 | +# API overview | |
| 2 | + | |
| 3 | +shithub exposes a small REST API at `/api/v1/`. It's | |
| 4 | +PAT-authenticated, JSON-bodied, and CSRF-exempt. | |
| 5 | + | |
| 6 | +> **Status.** The API is intentionally narrow today. Endpoints | |
| 7 | +> currently shipped: `GET /api/v1/user`, the | |
| 8 | +> `/api/v1/repos/{owner}/{repo}/check-runs` family, and the | |
| 9 | +> `/api/v1/user/starred*` stars endpoints. Other sections of this | |
| 10 | +> reference (Issues, Pull requests, Webhooks, etc.) describe the | |
| 11 | +> **planned** shape and will land in subsequent sprints. Pages | |
| 12 | +> that document planned-only endpoints carry a banner. | |
| 13 | + | |
| 14 | +## Authentication | |
| 15 | + | |
| 16 | +Every API request requires a personal access token. See | |
| 17 | +[Personal access tokens](../user/personal-access-tokens.md) for | |
| 18 | +how to create one. | |
| 19 | + | |
| 20 | +``` | |
| 21 | +Authorization: Bearer shp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
| 22 | +``` | |
| 23 | + | |
| 24 | +`Authorization: token shp_…` is also accepted as a synonym. | |
| 25 | + | |
| 26 | +A request with no `Authorization` header — or with an invalid / | |
| 27 | +expired / revoked PAT — returns `401 Unauthorized` with: | |
| 28 | + | |
| 29 | +```json | |
| 30 | +{"error": "unauthenticated"} | |
| 31 | +``` | |
| 32 | + | |
| 33 | +A request whose PAT lacks the scope a route requires returns | |
| 34 | +`403 Forbidden` with: | |
| 35 | + | |
| 36 | +```json | |
| 37 | +{"error": "insufficient scope"} | |
| 38 | +``` | |
| 39 | + | |
| 40 | +## Scopes | |
| 41 | + | |
| 42 | +Every route declares the scope(s) a token must hold. See | |
| 43 | +[scopes table](../user/personal-access-tokens.md#scopes). | |
| 44 | + | |
| 45 | +Scopes are **grants only** — a token cannot do something the | |
| 46 | +underlying user cannot. Holding `repo` does not let a token push | |
| 47 | +to a repo the user has no access to. | |
| 48 | + | |
| 49 | +## Conventions | |
| 50 | + | |
| 51 | +- **Base URL:** `https://<your-instance>/api/v1/` | |
| 52 | +- **Content type:** `application/json; charset=utf-8` for | |
| 53 | + request bodies and responses. | |
| 54 | +- **Error responses:** `{"error": "<short message>"}` with a | |
| 55 | + conventional HTTP status. | |
| 56 | +- **Cache-Control:** every API response sets `no-store`. | |
| 57 | +- **Pagination:** list endpoints accept `?per_page=` (default 30, | |
| 58 | + max 100) and return a `Link:` header with `next`, `prev`, | |
| 59 | + `first`, `last` URLs (RFC 5988). Cursor pagination on hot lists | |
| 60 | + uses `?cursor=…` and returns the next cursor in the `Link:` | |
| 61 | + header. | |
| 62 | +- **Body cap:** request bodies are capped at 256 KiB. Larger | |
| 63 | + payloads return `413`. | |
| 64 | +- **Rate limits:** every response includes `X-RateLimit-Limit`, | |
| 65 | + `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers (Unix | |
| 66 | + timestamp). Exceeding the limit returns `429`. | |
| 67 | + | |
| 68 | +## Versioning | |
| 69 | + | |
| 70 | +The path prefix `/api/v1/` is the version. Backwards-incompatible | |
| 71 | +changes will land under `/api/v2/`. Additions (new endpoints, new | |
| 72 | +fields on responses) are not breaking and land under v1. | |
| 73 | + | |
| 74 | +## Date format | |
| 75 | + | |
| 76 | +All timestamps are RFC 3339 UTC: `2026-05-09T16:30:00Z`. | |
| 77 | + | |
| 78 | +## ID stability | |
| 79 | + | |
| 80 | +Numeric IDs are stable for the life of the row; reusing a name | |
| 81 | +slot doesn't reuse the ID. URLs that take a `{owner}` and `{repo}` | |
| 82 | +will redirect after a rename — but external callers should | |
| 83 | +prefer numeric IDs where the API exposes them. | |
docs/public/api/pulls.mdadded@@ -0,0 +1,23 @@ | ||
| 1 | +# Pull requests | |
| 2 | + | |
| 3 | +> **Planned.** Pull request endpoints are not yet shipped. | |
| 4 | + | |
| 5 | +## Planned routes | |
| 6 | + | |
| 7 | +| Method | Path | Scope | | |
| 8 | +|--------|----------------------------------------------------------|--------------| | |
| 9 | +| GET | `/api/v1/repos/{owner}/{repo}/pulls` | `repo:read` | | |
| 10 | +| GET | `/api/v1/repos/{owner}/{repo}/pulls/{number}` | `repo:read` | | |
| 11 | +| POST | `/api/v1/repos/{owner}/{repo}/pulls` | `repo` | | |
| 12 | +| PATCH | `/api/v1/repos/{owner}/{repo}/pulls/{number}` | `repo` | | |
| 13 | +| GET | `/api/v1/repos/{owner}/{repo}/pulls/{number}/files` | `repo:read` | | |
| 14 | +| GET | `/api/v1/repos/{owner}/{repo}/pulls/{number}/commits` | `repo:read` | | |
| 15 | +| GET | `/api/v1/repos/{owner}/{repo}/pulls/{number}/reviews` | `repo:read` | | |
| 16 | +| POST | `/api/v1/repos/{owner}/{repo}/pulls/{number}/reviews` | `repo` | | |
| 17 | +| PUT | `/api/v1/repos/{owner}/{repo}/pulls/{number}/merge` | `repo` | | |
| 18 | +| GET | `/api/v1/repos/{owner}/{repo}/pulls/{number}/comments` | `repo:read` | | |
| 19 | +| POST | `/api/v1/repos/{owner}/{repo}/pulls/{number}/comments` | `repo` | | |
| 20 | + | |
| 21 | +The merge endpoint is gated by branch protection: status checks, | |
| 22 | +required reviewers, and conversation-resolution rules apply | |
| 23 | +identically to API-driven and UI-driven merges. | |
docs/public/api/repos.mdadded@@ -0,0 +1,31 @@ | ||
| 1 | +# Repositories | |
| 2 | + | |
| 3 | +> **Planned.** The repository CRUD API surface is not yet | |
| 4 | +> shipped. Today the repo lifecycle is driven through the web UI | |
| 5 | +> and the `shithubd` CLI. The shape below is the **planned** v1 | |
| 6 | +> surface; it will land in a follow-up sprint. | |
| 7 | + | |
| 8 | +## Planned routes | |
| 9 | + | |
| 10 | +| Method | Path | Scope | Purpose | | |
| 11 | +|--------|---------------------------------------------|--------------|-------------------------------| | |
| 12 | +| GET | `/api/v1/repos/{owner}/{repo}` | `repo:read` | Get one repo. | | |
| 13 | +| POST | `/api/v1/user/repos` | `repo` | Create a repo under the user. | | |
| 14 | +| POST | `/api/v1/orgs/{org}/repos` | `repo,admin:org` | Create a repo under an org. | | |
| 15 | +| PATCH | `/api/v1/repos/{owner}/{repo}` | `repo` | Edit settings. | | |
| 16 | +| DELETE | `/api/v1/repos/{owner}/{repo}` | `repo` | Delete (with confirmation). | | |
| 17 | +| GET | `/api/v1/repos/{owner}/{repo}/branches` | `repo:read` | List branches. | | |
| 18 | +| GET | `/api/v1/repos/{owner}/{repo}/branches/{branch}/protection` | `repo:read` | Get branch protection rules. | | |
| 19 | +| PUT | `/api/v1/repos/{owner}/{repo}/branches/{branch}/protection` | `repo` | Replace branch protection. | | |
| 20 | + | |
| 21 | +The web UI's behavior is the de-facto specification — when these | |
| 22 | +endpoints land, they implement the same checks (visibility, name | |
| 23 | +collisions, owner-permissions, soft-delete grace) that the web | |
| 24 | +forms enforce. | |
| 25 | + | |
| 26 | +## Today | |
| 27 | + | |
| 28 | +Until the API ships, scripted repo lifecycle is best done via | |
| 29 | +the `shithubd` operator CLI on the host (operator-only) or | |
| 30 | +through HTML form submission with a session cookie (per-user but | |
| 31 | +not API-shaped). | |
docs/public/api/search.mdadded@@ -0,0 +1,43 @@ | ||
| 1 | +# Search | |
| 2 | + | |
| 3 | +> **Planned.** Search over the API is not shipped yet. The web UI's | |
| 4 | +> `/search` is the only entry point today. | |
| 5 | + | |
| 6 | +## Planned routes | |
| 7 | + | |
| 8 | +| Method | Path | Scope | | |
| 9 | +|--------|-----------------------------------|--------------------------------| | |
| 10 | +| GET | `/api/v1/search/code` | None (public corpus only without `repo:read`); `repo:read` to include private. | | |
| 11 | +| GET | `/api/v1/search/repositories` | Same scoping. | | |
| 12 | +| GET | `/api/v1/search/issues` | Same scoping. | | |
| 13 | +| GET | `/api/v1/search/users` | None. | | |
| 14 | + | |
| 15 | +Query parameters: | |
| 16 | + | |
| 17 | +- `q=` — search query, with the same operators as | |
| 18 | + [Search (user docs)](../user/search.md). | |
| 19 | +- `sort=` — `created`, `updated`, `stars`, `relevance` (default). | |
| 20 | +- `order=` — `asc`, `desc`. | |
| 21 | +- `per_page=`, `cursor=`. | |
| 22 | + | |
| 23 | +Response shape (proposed): | |
| 24 | + | |
| 25 | +```json | |
| 26 | +{ | |
| 27 | + "total_count": 142, | |
| 28 | + "items": [ | |
| 29 | + { /* type-dependent record */ } | |
| 30 | + ] | |
| 31 | +} | |
| 32 | +``` | |
| 33 | + | |
| 34 | +The total is **counted to a cap** (10000) — for larger result | |
| 35 | +sets the API returns "10000+" semantics rather than counting | |
| 36 | +exactly. Consumers that need totals should narrow the query. | |
| 37 | + | |
| 38 | +## Visibility | |
| 39 | + | |
| 40 | +Search results are filtered by the requesting PAT's user's | |
| 41 | +visibility, identical to the web UI's behavior. A token cannot | |
| 42 | +see a result it would not see in a browser logged in as the | |
| 43 | +same user. | |
docs/public/api/users.mdadded@@ -0,0 +1,89 @@ | ||
| 1 | +# Users | |
| 2 | + | |
| 3 | +## Get the authenticated user | |
| 4 | + | |
| 5 | +``` | |
| 6 | +GET /api/v1/user | |
| 7 | +``` | |
| 8 | + | |
| 9 | +Required scope: `user:read`. | |
| 10 | + | |
| 11 | +Returns the user record for the account that owns the | |
| 12 | +authenticating PAT. | |
| 13 | + | |
| 14 | +### Response | |
| 15 | + | |
| 16 | +```json | |
| 17 | +{ | |
| 18 | + "id": 42, | |
| 19 | + "username": "alice", | |
| 20 | + "name": "Alice Example", | |
| 21 | + "email_verified": true, | |
| 22 | + "created_at": "2026-05-09T16:30:00Z" | |
| 23 | +} | |
| 24 | +``` | |
| 25 | + | |
| 26 | +| Field | Type | Notes | | |
| 27 | +|------------------|---------|------------------------------------------------------| | |
| 28 | +| `id` | int64 | Stable numeric ID. | | |
| 29 | +| `username` | string | Account username; URL-safe slug. | | |
| 30 | +| `name` | string | Display name; may be empty if not set. | | |
| 31 | +| `email_verified` | bool | Whether the primary email has been verified. | | |
| 32 | +| `created_at` | string | RFC 3339 UTC timestamp of account creation. | | |
| 33 | + | |
| 34 | +### Errors | |
| 35 | + | |
| 36 | +| Status | When | | |
| 37 | +|-------:|-------------------------------------| | |
| 38 | +| 401 | PAT missing/invalid/expired/revoked. | | |
| 39 | +| 403 | PAT lacks `user:read` scope. | | |
| 40 | +| 404 | User record not found (suspended or deleted between auth and lookup). | | |
| 41 | + | |
| 42 | +## Get a user by username | |
| 43 | + | |
| 44 | +> **Planned.** `GET /api/v1/users/{username}` is not shipped yet. | |
| 45 | + | |
| 46 | +## Update the authenticated user | |
| 47 | + | |
| 48 | +> **Planned.** `PATCH /api/v1/user` is not shipped yet. | |
| 49 | + | |
| 50 | +## List the authenticated user's repos | |
| 51 | + | |
| 52 | +> **Planned.** `GET /api/v1/user/repos` is not shipped yet. | |
| 53 | + | |
| 54 | +## Stars | |
| 55 | + | |
| 56 | +The starred-repos surface for the authenticating user. | |
| 57 | + | |
| 58 | +### List starred repos | |
| 59 | + | |
| 60 | +``` | |
| 61 | +GET /api/v1/user/starred | |
| 62 | +``` | |
| 63 | + | |
| 64 | +Required scope: `user:read`. | |
| 65 | + | |
| 66 | +Returns the list of `(owner, repo)` pairs the user has starred, | |
| 67 | +most-recent first. Pagination via `?cursor=…` and `?per_page=`. | |
| 68 | + | |
| 69 | +### Star a repo | |
| 70 | + | |
| 71 | +``` | |
| 72 | +PUT /api/v1/user/starred/{owner}/{repo} | |
| 73 | +``` | |
| 74 | + | |
| 75 | +Required scope: `user` (write). | |
| 76 | + | |
| 77 | +Idempotent: starring an already-starred repo returns `204` and | |
| 78 | +does not duplicate the row. Returns `404` if the repo doesn't | |
| 79 | +exist or the user can't see it. | |
| 80 | + | |
| 81 | +### Unstar a repo | |
| 82 | + | |
| 83 | +``` | |
| 84 | +DELETE /api/v1/user/starred/{owner}/{repo} | |
| 85 | +``` | |
| 86 | + | |
| 87 | +Required scope: `user` (write). | |
| 88 | + | |
| 89 | +Idempotent: unstarring a not-starred repo returns `204`. | |
docs/public/api/webhooks.mdadded@@ -0,0 +1,57 @@ | ||
| 1 | +# Webhooks | |
| 2 | + | |
| 3 | +The webhook **delivery format** (payloads, signing) is shipped | |
| 4 | +and stable. The webhook **management API** (CRUD over webhooks | |
| 5 | +on a repo) is planned. | |
| 6 | + | |
| 7 | +## Delivery format | |
| 8 | + | |
| 9 | +See [Webhooks (user docs)](../user/webhooks.md) for the full | |
| 10 | +delivery contract — headers, body framing, signature verification, | |
| 11 | +retries, idempotency. | |
| 12 | + | |
| 13 | +The user-docs page is intentionally the canonical place; an API | |
| 14 | +consumer building a subscriber endpoint reads the same material. | |
| 15 | + | |
| 16 | +## Management API (planned) | |
| 17 | + | |
| 18 | +| Method | Path | Scope | | |
| 19 | +|--------|-----------------------------------------------------------|--------------| | |
| 20 | +| GET | `/api/v1/repos/{owner}/{repo}/hooks` | `webhooks` | | |
| 21 | +| POST | `/api/v1/repos/{owner}/{repo}/hooks` | `webhooks` | | |
| 22 | +| GET | `/api/v1/repos/{owner}/{repo}/hooks/{id}` | `webhooks` | | |
| 23 | +| PATCH | `/api/v1/repos/{owner}/{repo}/hooks/{id}` | `webhooks` | | |
| 24 | +| DELETE | `/api/v1/repos/{owner}/{repo}/hooks/{id}` | `webhooks` | | |
| 25 | +| POST | `/api/v1/repos/{owner}/{repo}/hooks/{id}/pings` | `webhooks` | | |
| 26 | +| GET | `/api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries` | `webhooks` | | |
| 27 | +| POST | `/api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries/{delivery}/redeliver` | `webhooks` | | |
| 28 | + | |
| 29 | +Until these land, manage webhooks via the web UI under | |
| 30 | +Repository → Settings → Webhooks. | |
| 31 | + | |
| 32 | +## Event types (canonical list) | |
| 33 | + | |
| 34 | +The events shippable today, by `X-Shithub-Event` header: | |
| 35 | + | |
| 36 | +- `push` | |
| 37 | +- `pull_request` (actions: `opened`, `closed`, `merged`, | |
| 38 | + `reopened`, `edited`, `ready_for_review`, `converted_to_draft`, | |
| 39 | + `synchronize`) | |
| 40 | +- `pull_request_review` (actions: `submitted`, `dismissed`) | |
| 41 | +- `pull_request_review_comment` | |
| 42 | +- `issues` (actions: `opened`, `closed`, `reopened`, `edited`, | |
| 43 | + `assigned`, `unassigned`, `labeled`, `unlabeled`) | |
| 44 | +- `issue_comment` | |
| 45 | +- `check_run` (actions: `created`, `completed`, `rerequested`) | |
| 46 | +- `check_suite` (actions: `requested`, `completed`, | |
| 47 | + `rerequested`) | |
| 48 | +- `star` | |
| 49 | +- `fork` | |
| 50 | +- `repository` (actions: `created`, `deleted`, `archived`, | |
| 51 | + `unarchived`, `renamed`, `transferred`, `publicized`, | |
| 52 | + `privatized`) | |
| 53 | +- `ping` (test event you trigger manually) | |
| 54 | + | |
| 55 | +Each event's payload is documented per-type in the webhook detail | |
| 56 | +page's "Recent deliveries" inspector — that's currently the | |
| 57 | +authoritative reference until per-event documentation lands here. | |