neosourceDocs
Search docs

List the authenticated user's GitHub repositories

GET/api/github/repos

listGithubRepos

Lists repos from the caller's linked GitHub identity for the import picker. With no `visibility` param it returns the widest view the granted scope allows — private repos included once the identity carries the `repo` scope (Tier 2), public-only before that — and reports which of the two happened via `can_list_private`. Passing `visibility=private`/`all` without the scope is a `403 NeedsScopeError` instead.

Requires authentication using a session cookie or a bearer token — see tokens and scopes.

curl

curl -X GET 'https://neosource.dev/api/github/repos' \
  -H 'Authorization: Bearer $NEOSOURCE_TOKEN'

fetch

fetch("https://neosource.dev/api/github/repos", {
  method: "GET",
  headers: {
    Authorization: "Bearer $NEOSOURCE_TOKEN",
  },
});

Query parameters

visibility

One of `public`, `private`, `all`. Omitted means **auto**: the widest view the granted scope allows — `all` when the linked identity carries the `repo` scope (Tier 2), `public` otherwise. Asking for `private`/`all` *explicitly* is a demand rather than a preference, so it returns `403 NeedsScopeError` when the scope is missing instead of silently degrading to public-only.

string

Responses

200GitHub repositories

application/json

GithubRepoListResponse

object

app_connections_url

string | null

Where the user manages *this deployment's* OAuth app on GitHub — `https://github.com/settings/connections/applications/{client_id}`. That page is the only place an organization's access can be granted (as an owner) or requested (as a member), which is what makes a whole organization's repositories missing from `repos` fixable. Absent when GitHub is not configured on the deployment, so the SPA renders the affordance from the response rather than guessing. This is not a scope signal and cannot be one: GitHub does not enumerate the organizations an unapproved OAuth app is restricted from, so the picker cannot name them — it can only point at the page that lists them.

can_list_privaterequired

boolean

Whether `repos` was allowed to include private repositories — i.e. the linked GitHub identity's token carries the `repo` scope (Tier 2). `false` means the list is public-only *by scope, not by choice*, which is what the picker turns into a "grant access to private repositories" prompt. Lets the SPA render the right empty/CTA state from the list response alone, with no second round trip to read granted scopes.

reposrequired

array

items

GithubRepoSummary

object

A GitHub repo as offered in the import picker. Mirrors the trimmed `neosource_engine::github_api::GithubRepo` (mapped in the route — DTOs never depend on the engine).

default_branch

string | null

description

string | null

full_namerequired

string

`owner/name` — the import addressing key.

html_url

string | null

The repo's page on github.com, so the picker can link a row out to its source. Server-supplied rather than built client-side from `full_name`: the URL's host is a fact about the provider, not something the SPA should hard-code.

language

string | null

namerequired

string

owner_loginrequired

string

privaterequired

boolean

size_kbrequired

integerint64

Disk size in KiB, as GitHub reports it.

403Forbidden — one of: forbidden, needs_scope

application/json

one of
  • ErrorForbidden
  • NeedsScopeError

    object

    `403` body returned when listing private repos but the linked identity lacks the required provider scope. The SPA turns this into an incremental-authorization prompt (Tier 2) that calls the `/elevate` OAuth endpoint with this `scope`.

    errorrequired

    string

    Always `needs_scope` — this body exists to carry the extra fields that kind needs.

    "needs_scope"

    scoperequired

    string

    The provider scope to request via elevation (e.g. `"repo"`).

Standard errors

Bodies documented once for the whole API — see standard errors.

  • 400Bad Request — one of: invalid_input
  • 401Authentication required
  • 429Rate limited — retry after the `Retry-After` header
  • 500Internal server error
  • 502Bad Gateway — one of: upstream
  • 503Service temporarily unavailable / at capacity — retry after the `Retry-After` header
  • 504Gateway timeout — the request exceeded the server's handling budget