Forks
Manage a repo's fork network. Mirrors GitHub's
/repos/{owner}/{repo}/forks shape.
Scopes: repo:read on GET, repo:write on POST. Policy gates
are ActionRepoRead and ActionForkCreate. See
common API conventions for envelopes and headers.
List forks
GET /api/v1/repos/{owner}/{repo}/forks[?page=&per_page=]
Paginated, recency-sorted, soft-deleted rows excluded. Per-row visibility filter applies — a private fork of a public repo only surfaces to viewers who can see the fork.
[
{
"id": 101,
"name": "demo",
"owner_login": "bob",
"owner_display_name": "Bob",
"description": "",
"visibility": "public",
"star_count": 0,
"fork_count": 0,
"init_status": "initialized",
"created_at": "2026-05-12T15:00:00Z"
}
]
init_status is one of init_pending / initialized /
init_failed — clients can poll the single-repo endpoint to
watch a fresh fork transition out of init_pending.
Create a fork
POST /api/v1/repos/alice/demo/forks
Authorization: Bearer <pat>
Content-Type: application/json
{
"name": "demo-fork",
"visibility": "private"
}
All fields are optional:
name— repo name on the caller's account. Defaults to the source repo's name. Forking your own repo into the same name is refused (409); pass a differentname.visibility— must be ≤ source visibility. A public source can fork to private; a private source is pinned to private.
Targets the authenticated user's namespace only today. Org targets land in a follow-up.
Returns 201 Created with the persisted row immediately. The
on-disk git clone --bare --shared runs in the background
worker (repo:fork_clone kind), so the response carries
init_status: "init_pending" and the fork's URL resolves right
away.
{
"id": 101,
"name": "demo-fork",
"owner_login": "bob",
"visibility": "public",
"init_status": "init_pending",
"source_repo_id": 42,
"default_branch": "trunk",
"created_at": "2026-05-12T15:00:00Z"
}
Errors
404— source repo not visible.409— self-fork with nonameoverride, target name collides with an existing repo, or source archived.422—visibilityexceeds source visibility.
View source
| 1 | # Forks |
| 2 | |
| 3 | Manage a repo's fork network. Mirrors GitHub's |
| 4 | `/repos/{owner}/{repo}/forks` shape. |
| 5 | |
| 6 | Scopes: `repo:read` on GET, `repo:write` on POST. Policy gates |
| 7 | are `ActionRepoRead` and `ActionForkCreate`. See |
| 8 | [common API conventions](overview.md) for envelopes and headers. |
| 9 | |
| 10 | ## List forks |
| 11 | |
| 12 | ``` |
| 13 | GET /api/v1/repos/{owner}/{repo}/forks[?page=&per_page=] |
| 14 | ``` |
| 15 | |
| 16 | Paginated, recency-sorted, soft-deleted rows excluded. Per-row |
| 17 | visibility filter applies — a private fork of a public repo |
| 18 | only surfaces to viewers who can see the fork. |
| 19 | |
| 20 | ```json |
| 21 | [ |
| 22 | { |
| 23 | "id": 101, |
| 24 | "name": "demo", |
| 25 | "owner_login": "bob", |
| 26 | "owner_display_name": "Bob", |
| 27 | "description": "", |
| 28 | "visibility": "public", |
| 29 | "star_count": 0, |
| 30 | "fork_count": 0, |
| 31 | "init_status": "initialized", |
| 32 | "created_at": "2026-05-12T15:00:00Z" |
| 33 | } |
| 34 | ] |
| 35 | ``` |
| 36 | |
| 37 | `init_status` is one of `init_pending` / `initialized` / |
| 38 | `init_failed` — clients can poll the single-repo endpoint to |
| 39 | watch a fresh fork transition out of `init_pending`. |
| 40 | |
| 41 | ## Create a fork |
| 42 | |
| 43 | ```http |
| 44 | POST /api/v1/repos/alice/demo/forks |
| 45 | Authorization: Bearer <pat> |
| 46 | Content-Type: application/json |
| 47 | |
| 48 | { |
| 49 | "name": "demo-fork", |
| 50 | "visibility": "private" |
| 51 | } |
| 52 | ``` |
| 53 | |
| 54 | All fields are optional: |
| 55 | |
| 56 | - `name` — repo name on the caller's account. Defaults to the |
| 57 | source repo's name. Forking your own repo into the same name |
| 58 | is refused (409); pass a different `name`. |
| 59 | - `visibility` — must be ≤ source visibility. A public source |
| 60 | can fork to private; a private source is pinned to private. |
| 61 | |
| 62 | Targets the **authenticated user's namespace only** today. Org |
| 63 | targets land in a follow-up. |
| 64 | |
| 65 | Returns `201 Created` with the persisted row immediately. The |
| 66 | on-disk `git clone --bare --shared` runs in the background |
| 67 | worker (`repo:fork_clone` kind), so the response carries |
| 68 | `init_status: "init_pending"` and the fork's URL resolves right |
| 69 | away. |
| 70 | |
| 71 | ```json |
| 72 | { |
| 73 | "id": 101, |
| 74 | "name": "demo-fork", |
| 75 | "owner_login": "bob", |
| 76 | "visibility": "public", |
| 77 | "init_status": "init_pending", |
| 78 | "source_repo_id": 42, |
| 79 | "default_branch": "trunk", |
| 80 | "created_at": "2026-05-12T15:00:00Z" |
| 81 | } |
| 82 | ``` |
| 83 | |
| 84 | ## Errors |
| 85 | |
| 86 | - `404` — source repo not visible. |
| 87 | - `409` — self-fork with no `name` override, target name |
| 88 | collides with an existing repo, or source archived. |
| 89 | - `422` — `visibility` exceeds source visibility. |