Read repositories, inspect commits, track issues, and connect your tools to git.bvdl.io. This reference covers every JSON endpoint under /api/v1 and /api.
BASE URLhttps://git.bvdl.io/api/v1v1
Alpha API. Endpoints and response fields can change without a deprecation period, and data can be wiped by a reset. Keep polling gentle. About the alpha
Hosting integrations can use OAuth and OpenID Connect for sign-in, selected repository access and signed deployment webhooks.
Your first request
Public repository reads work without a token. Try listing the first page:
Send JSON request bodies with Content-Type: application/json. Examples use $TOKEN for your personal access token.
Path conventions
{owner} is the owner namespace; {repository} is the repository name without .git. Replace placeholders with your values and URL-encode path and query values. {number} is a repository-local issue or pull request number; {release} is a numeric release ID; {sha} is a full commit ID.
Create a personal access token in Settings → Tokens, then send it as a Bearer token. API authentication uses the token, rather than your browser session. No CSRF token is needed for these API routes.
Most v1 GET endpoints accept anonymous requests for public data. A supplied invalid token still returns 401.
Token required
/user, /search, your stars and watches, and every write require a valid token. Private repository reads require permission.
read scope
Read access only. A token does not grant repository access its owner does not already have.
write scope
Includes read access. Mutations also check the repository permissions listed for each endpoint.
Full access
Tokens with no scopes (null or an empty list) permit read and write, subject to the holder’s permissions.
Missing required, invalid, expired, or revoked tokens return 401. Tokens belonging to suspended accounts are also rejected. HTTP Basic authentication is supported with the token as the password, for example curl -u "username:$TOKEN".
Successful reads and updates return 200; creation returns 201. A single resource is wrapped in data. Examples throughout this page show the actual field names with illustrative values.
Paginated collections return data as an array and meta as an object. IDs and counts are numbers, flags are booleans, and timestamps use ISO 8601. Nullable fields are returned as null; fields conditionally included by an endpoint are called out below.
Empty bodies and special envelopes. A 204 No Content response has no body—skip JSON parsing. Search returns named result groups, and the contribution graph returns weeks. Unversioned endpoints have different metadata and errors.
List endpoints in both API versions accept an integer page from 1 to 100000 (default 1) and an integer per_page from 1 to 100 (default 30). Malformed, empty, or out-of-range pagination values return 422 with field errors.
Increment page until it reaches meta.last_page. Pages beyond the collection return an empty data array. No pagination links or cursors are returned. Search and contribution graphs do not use this envelope.
For v1 request errors, error is a message string. Use the HTTP status for control flow; message text may vary. Validation errors add a top-level fields map of field names to arrays of messages.
422 Unprocessable Content · application/json
{
"error": "The title field is required.",
"fields": {
"title": [
"The title field is required."
]
}
}
HTTP status codes
Status
Meaning
200
Success; JSON response body.
201
Resource created, or commit status recorded; JSON response body.
204
Success; no response body.
401
A required token is missing, or the supplied credential is invalid.
403
The token scope or account permissions do not allow this action.
404
Resource not found, or a private repository is not readable by the caller.
405
This path does not support the requested HTTP method.
409
The pull request cannot be merged in its current state, or a branch changed.
422
Request validation failed. Check the fields map.
429
Rate limit exceeded. Wait before retrying.
5xx
Server failure. Retry with backoff; a JSON error envelope is not guaranteed for unexpected or upstream failures.
A merge waiting for commit indexing returns 409 with code: indexing_pending. No merge was performed. Wait at least the Retry-After seconds before retrying the merge with the same reviewed sha; use bounded retries with backoff if it remains pending. The delay is guidance, not a guarantee that indexing will have finished.
409 Conflict · Retry-After: 5 · /api/v1
{
"error": "Commit history is still being indexed. Nothing was merged; wait at least 5 seconds, then refresh the pull request or retry the merge.",
"code": "indexing_pending",
"retry_after": 5
}
Query filters must have the documented types and allowed values; arrays such as ?state[]=open return 422. Omitted or empty optional filters use their defaults. Unknown label names and milestone IDs simply match no issues.
A private repository you may not read returns 404, exactly like a nonexistent repository: {"error":"Not found."}.
The v1 API allows 60 requests per minute per authenticated token owner, or per IP for anonymous requests. Multiple tokens for one account share the same budget. Unversioned API routes (including contribution graphs) have a separate budget of 120 per minute per token owner, or 60 per minute per anonymous IP.
For v1 responses, inspect X-RateLimit-Limit and X-RateLimit-Remaining. On 429, wait the seconds specified by Retry-After. The v1 rate-limit body also supplies retry_after:
429 Too Many Requests · /api/v1
{
"error": "Too many requests. Please slow down and try again later.",
"retry_after": 60
}
User fields: id (integer), username and name (strings), bio and avatar_url (nullable strings), created_at (nullable timestamp). avatar_url is an application-served upload URL or null; external avatar URLs are never returned. Nested users use the same fields. Deleted issue, pull request, and release authors are represented by null.
Read repository metadata and manage repositories under your own account. These endpoints do not upload files or Git objects; use Git to push your code.
Creates a repository owned by the token holder. Organization ownership is not supported here.
Write-capable token required.
JSON body fields
Parameter
Description
namestring · required
Up to 100 characters; trimmed and lowercased. Start with a letter or digit, then letters, digits, dots, underscores or hyphens. Must be unique for the owner, not reserved, and not end in .git.
descriptionstring | null
Optional description, up to 1,000 characters.
privateboolean
Whether the repository is private. Defaults to false on creation.
default_branchstring | null
Optional, up to 255 characters. A short name such as main becomes refs/heads/main. Defaults to null.
Counts and IDs are integers; private and fork are booleans; topics is a string array. description, default_branch, primary_language, forked_from_id and pushed_at can be null. clone_url is an absolute HTTPS/HTTP URL on this instance. topics is included on reads and updates but omitted on creation.
sha, tree and message are strings. Git author and committer objects contain name, email and a nullable date, distinct from user profile resources. parents (string array) and stats (integer counts) appear only on the detail endpoint. Stats fall back to zero if stored objects are unavailable.
Creates or replaces the status for this SHA and context. The commit must exist in the repository or be the current head of an open pull request from a fork; otherwise 404.
Requires a write-capable token and repository admin permission.
JSON body fields
Parameter
Description
contextstring · required
Up to 100 characters. Start with a letter or digit; then letters, digits, dots, underscores, slashes or hyphens.
commit_id, context and state are strings. description is nullable; updated_at is a timestamp. Status history is replaced per context rather than appended.
Paginated, newest first. All supplied label names must match.
Public read; a token is needed for private repositories.
Query parameters
Parameter
Description
statequery · string
open (default), closed, or all. Unknown values return 422.
labelsquery · string
Comma-separated label names, such as bug,documentation. At most 20 names of up to 50 characters each, and 1,024 characters in total. Whitespace and empty entries are ignored.
milestonequery · integer
Optional positive milestone ID (up to 9223372036854775807). Unknown IDs or IDs from another repository return an empty list.
number and comments are integers; comments is a count, not comment bodies. body, author, milestone and closed_at can be null. Labels contain id, name and color. Milestones contain id, title, state and nullable due_date. Timestamps use ISO 8601.
base and head must be different, existing short branch names in this same repository. Invalid branches return 422. Cross-repository creation is not supported.
Requires a write-capable token and repository push permission.
JSON body fields
Parameter
Description
titlestring · required
Up to 255 characters.
bodystring | null
Optional Markdown text, up to 65,535 characters.
basestring · required
Target branch, up to 255 characters, for example main.
headstring · required
Source branch, up to 255 characters, for example docs.
Use the per-repository pull request number. Unknown numbers return 404. Send Accept: application/vnd.github.diff to retrieve a raw Git unified diff instead of the JSON detail.
Public read; a token is needed for private repositories.
Query parameters
Parameter
Description
include_diff_statsquery · boolean (0 or 1)
Defaults to 0: JSON detail omits diff_stats and reads no file contents or commit history, making it suitable for status polling. Set to 1 to compute commits, changed_files, additions, deletions and available. Existing clients using diff_stats must add include_diff_stats=1. Diff content is loaded separately through /diff or the raw diff Accept header.
Compares the merge base to the head. Open requests use current branch tips (saved tips if a branch was deleted); closed and merged requests use saved snapshots. Public forks are supported; a head that can no longer be disclosed returns 404. Defaults to structured JSON; send Accept: application/vnd.github.diff for raw Git unified diff text. Unknown PRs return 404, invalid numeric numbers return 422, unsupported media types return 406. Raw requests return 409 when objects or the merge base are unavailable and 422 when a complete diff exceeds limits; errors always use the JSON error envelope.
Public read; a token is needed for private repositories.
Query parameters
Parameter
Description
Acceptheader · optional
application/json (default) or application/vnd.github.diff. Also accepts application/vnd.github.v3.diff, application/x-diff and text/plain. Quality weights are honored. Raw responses use the selected media type and Vary: Accept.
Uses the same merge behavior and branch protections as the web interface: fast-forward when possible, otherwise a merge commit. Supports existing pull requests from forks. Returns the merged pull request with state, merged_at, merged_by and merge_commit populated. The merge_commit is the resulting base tip (the head for a fast-forward). Indexing and webhook delivery complete asynchronously. No body is required. Returns 409 for closed requests, conflicts, missing branches, nothing to merge, unmet reviews or status checks, quota limits, or changed branches. If current branch history is not fully indexed, returns 409 with code indexing_pending, retry_after in seconds and a Retry-After header. This response leaves the pull request and branches unchanged. Wait at least that long before retrying; use bounded retries with backoff if indexing remains pending. Keep the reviewed sha on retries so a newer push requires review. Storage write failures return 503. Repeating this request after a successful merge returns 200 with the saved result without merging or emitting events again, even if branches have moved or been deleted. If sha is supplied it must match the saved merged head; a mismatch still returns 409. GET pull request details also includes merge_commit; it is null for historical merges made before this field was recorded.
Requires a write-capable token and repository push permission.
JSON body fields
Parameter
Description
shastring · optional
Expected current head commit: exactly 40 lowercase hexadecimal characters. A mismatch returns 409 without merging. Omit to merge the current head; malformed or null values return 422.
number is an integer. state is open, closed or merged. base_ref and head_ref are short branch names; base_commit and head_commit are commit IDs. body, author, merged_at and merged_by can be null. merged_by uses the User resource. The /diff JSON data contains available, truncated, changed_files, additions, deletions and files. Each file has filename, status (added/modified/deleted), additions, deletions, binary, available, too_large, base_mode, head_mode and patch (a complete per-file Git diff, or null for binary, oversized or missing blobs). Totals cover only returned, computed files; available describes the comparison baseline, so also check each file. At most 500 files are returned; truncated flags omitted files. Blobs over 1 MiB are not loaded; text rendering is bounded to 512 KiB per side, 5,000 combined lines and 1,000,000 comparison cells. Request-wide read budgets can also return 422. JSON replaces invalid UTF-8 with replacement characters; raw text preserves bytes. Renames appear as deletion plus addition. Raw binary changes use Git binary-difference notices, not binary patches. File modes, submodules and missing final newlines are preserved. Responses are private and not cacheable. Patch/email format is not supported.
Read release metadata. Creating releases and uploading assets are currently available through the web interface only. Drafts are visible only to callers who may manage releases; others receive 404 for a draft.
IDs and counts are integers; draft and prerelease are booleans. body, author and published_at can be null. Asset size is bytes. download_url is an absolute web URL (or null when unavailable); private downloads require web authorization and do not use these API token routes.
Stars bookmark a repository; watches subscribe to activity. All PUT and DELETE operations here are idempotent and return 204 with an empty body, even when already in the requested state. They need read access to the repository and a write-capable token.
Repository and issue results are scoped to public repositories and the caller’s own private repositories. Unselected groups remain present as empty arrays.
Token required.
Query parameters
Parameter
Description
qquery · string · required
Search text, up to 255 characters.
typequery · string
repos, users, or issues. Omit to search all three groups.
This example shows an unfiltered search across all three groups. Search returns lean objects as shown, rather than full API resources. Repositories are sorted by stars then name; users by username; open issues by newest ID.
Register clients under Settings → Applications. Use authorization codes with S256 PKCE, an exact HTTPS callback, state, and an OIDC nonce. Consent selects repositories explicitly. Access tokens last one hour; refresh tokens rotate and last 30 days, with an absolute 90-day connection lifetime.
Discover issuer, protocol URLs and supported capabilities. Validate ID tokens using the advertised RS256 signing keys, issuer, client audience and original nonce.
Required query parameters: response_type=code, client_id, redirect_uri, scope, state, code_challenge, code_challenge_method=S256. Include nonce for OIDC. The user logs in and selects repositories. Consent is always explicit.
Send grant_type=authorization_code, code, redirect_uri and code_verifier. To refresh, send grant_type=refresh_token and refresh_token; do not send scope. Store the new token pair atomically.
Client secret via Basic or client_secret_post. Public clients send client_id without a secret.
Response200 · access_token, refresh_token, expires_in, scope; id_token with openid
Scopes: openid, profile, email, repositories:read, webhooks:manage. OAuth supports /api/v1/user (profile), selected repository listing/details/branches and Git HTTPS clone/fetch (repositories:read), and connection-owned push webhooks (webhooks:manage plus repositories:read and current administrator rights). Other API actions and pushes are refused. Use a Git credential helper with username oauth2 and the access token as password. Reauthorize to change selected repositories or scopes. Suspension, security changes, permission loss and revocation are enforced on subsequent access and queued webhook delivery. The hosting backend must validate state and OIDC tokens, verify X-Webhook-Signature over the raw payload, deduplicate X-Webhook-Delivery and serialize deployment promotion.
Manage signed push hooks. OAuth clients can manage only hooks belonging to their exact connection; manually created hooks and other connections are isolated.
Push payloads include repository.id, ref, branch, before, after and pusher. Match the configured full branch ref and deploy the after commit. Verify X-Webhook-Signature (sha256= plus HMAC-SHA256 of the raw body) in constant time, and deduplicate X-Webhook-Delivery across retries. Branch deletion is a separate event and is not included in push-only subscriptions.
Organization reads are available on the unversioned API only. Both require a token and use the unversioned response format.
List your organizations
GET/api/orgs
Lists organizations you belong to, sorted by name. Accepts page and per_page. Returns 200 with a paginated organization list; each organization includes your role (owner or member).
Get an organization
GET/api/orgs/{org}
{org} is the organization slug. Returns 200 with member and visible repository counts, or 404 for an unknown slug. Members see the total repository count; nonmembers see only the public repository count.
IDs and counts are integers; name and slug are strings; description and avatar_url are nullable strings. avatar_url is currently null; organizations use generated initials. List items add role instead of member_count and repo_count.
Returns daily indexed commit counts. A username or public repository can be queried anonymously. With neither selector, a token is required and the graph belongs to the token holder. Private repositories require read permission; unknown or unreadable targets return 404.
Query parameters
Parameter
Description
usernamestring · optional
Username, up to 255 characters, case-insensitive. Counts commits matched by the user’s author email across repositories.
repositorystring · optional
owner/repository, up to 512 characters. Takes precedence over username when both are supplied.
weeks contains arrays of seven days, Sunday first, oldest week first through the current week. date is YYYY-MM-DD; count is an integer (zero on quiet or future days). There is no data or meta wrapper. Validation and missing-token errors use the unversioned nested shape; an invalid supplied token is rejected by authentication as {"error":"Unauthenticated."}.
The original endpoints remain available at /api. Every endpoint in the table below requires a token, including public repository reads. Use the documented paths and shapes for your selected API version; switching only the prefix is not sufficient.
All list endpoints accept page and per_page with the same defaults and caps as v1, but omit meta.last_page. Stop when page × per_page ≥ total. Single resources still use a data wrapper.
{
"error": {
"message": "The title field is required.",
"code": "validation_failed",
"fields": {
"title": [
"The title field is required."
]
}
}
}
Other errors use error.message and error.code, with codes such as unauthenticated, forbidden, not_found, method_not_allowed or http_error. Rate-limit errors use the standard unversioned HTTP-error envelope, with no v1 retry_after body field.
Unversioned endpoints (organization and contribution routes are documented above)
Endpoint / response
Parameters and permissions
GET/api/user
200 · Identity
The token holder: id, username and name only.
GET/api/repositories
200 · Repository list
Owned or directly collaborated repositories, most recently pushed first (never pushed last). No sort or direction filter.
POST/api/repositories
201 · Repository
Write-capable token. name and visibility (public or private) are required; description is optional and nullable. The name and description constraints match v1. No default_branch input.
GET/api/repositories/{owner}/{repository}
200 · Repository
Requires repository read access.
PUT/api/repositories/{owner}/{repository}
200 · Repository
Admin permission and a write-capable token. Optional description, visibility (public or private), and default_branch (existing full ref or null). Only supplied fields change.
DELETE/api/repositories/{owner}/{repository}
204 · Empty body
Admin permission and a write-capable token. Permanently deletes the repository.
Push permission and a write-capable token. Same optional sha field, merge behavior, branch protections and 409/503 outcomes as v1. Pending indexing returns 409 with error.code indexing_pending, top-level retry_after in seconds and a Retry-After header. Wait before retrying with the same reviewed sha. Returns state, merged_at and merged_by in the unversioned pull request shape.
Resource differences
Unversioned repository objects contain id, name, full_name, owner, visibility, private, default_branch, description, fork, pushed_at and created_at. Owner objects contain only id, username and name.
Issue and pull request fields match v1 except that nested users include only id, username and name, and issue milestones omit due_date. There is no unversioned issue update route. These routes do not expose v1 release, status, search, star or watch operations.