API Reference
Complete /api/v0 HTTP reference for git.eu: authentication, the response envelope, status semantics, every endpoint, and every problem type.
git.eu API Reference
Last updated: 2026-10-09
Overview
The git.eu HTTP API serves your repositories as JSON. Every instance exposes it on its own host, under /api/v0 - for example https://<INSTANCE>.git.eu/api/v0/repos.
v0is a beta surface. It is not frozen: routes, fields and problem types may change without a compatibility shim.- Requests and responses are JSON only. Send
Content-Type: application/jsonwith every request that carries a body. - Every route requires a bearer token. There is no anonymous access - see Authentication below.
Authentication
Every request carries a personal access token in the Authorization header:
Authorization: Bearer giteu_your_token
The token must hold the api scope. Create one under Settings - Tokens on your instance (https://<INSTANCE>.git.eu/settings/tokens), tick the api scope, and copy the value: it is shown once and never again. The Git Access guide walks through token creation in detail.
A token holding only the git scope works for git clone, fetch and push, but not for this API.
The API deliberately diverges from the website: there is no anonymous access, ever. A missing, malformed, expired or revoked token is answered 401 on every route - including a read of a public repository, which the website serves to signed-out visitors.
A valid token without the api scope is answered 403 with the insufficient_scope problem on every route.
Response Envelope
Every JSON body uses the same envelope: exactly one of data and error is set - never both, never neither.
| Member | Type | Required | Description |
|---|---|---|---|
data | payload or null | yes | The successful payload, or null on an error. |
error | error object or null | yes | The error object (see Errors), or null on success. |
links | object | no | Optional related URLs (self, next, prev). |
meta | object | no | Optional non-payload metadata. |
A successful response:
{
"data": {
"name": "my-repo",
"isPrivate": false
},
"error": null
}
A failed response, served as application/problem+json:
{
"data": null,
"error": {
"type": "not_found",
"title": "Not found",
"status": 404
}
}
Status Semantics
| Rule | Behavior |
|---|---|
| Authentication comes first | The bearer-token check runs before any access decision. An unauthenticated call is always 401, whatever the target repository is. |
| Hidden, never refused | A repository the token may not see is reported as not found, never as a distinguishable access error - the API never confirms that a private repository exists. |
| Batch always succeeds as a whole | A batch create replies 200 with a per-item result array. Each item carries its own outcome; the response status is never 207 and never reflects an item failure. |
| A verified email is required to change repositories | Creating, updating and deleting a repository need a verified email address on the token owner's account. Otherwise the call fails with the email_not_verified problem (403) - per item for a batch create. |
| Delete replies 204 | A successful delete returns 204 with an empty body - the only route that returns no envelope. |
| Validation is rejected up front | Request bodies, path parameters and query strings are schema-validated before any work happens; a violation is a 400 validation_failed problem. A missing required field, a wrong type, an empty repos array or an unknown field is refused - never stripped, converted or ignored. |
Endpoints
POST /api/v0/repos/batch
Creates one or more repositories owned by the calling token. This is the only create route: a single create is a one-item batch. Every item is attempted independently, so one failure never aborts the rest; the response is always 200 with a per-item result array (never 207).
| Property | Value |
|---|---|
| Access | Caller-scoped: the route only ever touches repositories owned by the token holder, so no per-repository access decision is made. |
| Success status | 200 |
| Success body | The standard JSON envelope, payload in data. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
repos | array of object (1-50 items) | yes | The repositories to create, 1 to 50 per call. Each item is attempted independently: one failing item never aborts the others. |
repos[].displayName | string (1-128 chars) | yes | Human-readable repository name. Required: it is never filled in from your account defaults. |
repos[].slug | string (1-128 chars) | no | URL slug of the repository. Omit it and a slug is generated from the display name; a value you send is always used as is. Letters, digits, ., _, -; starts and ends with a letter or digit; no two of ._- in a row; may not end in .git, .atom or .html; 1-128 characters. |
repos[].description | string (max 500 chars) | no | Free-text description. Omit it and the repository is created without one; a value you send is always used as is. |
repos[].isPrivate | boolean | no | True to create a private repository. Omit it and the repository is private; send false to create a public one. |
repos[].defaultBranch | string (max 255 chars) | no | Name of the default branch. Omit it and your account default applies; a value you send always wins. |
Response payload
The envelope's data member is an array; each element carries:
| Field | Type | Required | Description |
|---|---|---|---|
index | number | yes | Zero-based position of the item in the submitted repos array. |
status | string (one of created, failed) | yes | Outcome of this item: created on success, failed otherwise. |
repo | object | no | A repository as returned by the API. |
repo.owner | string | yes | Username of the repository owner (the bearer token's user). |
repo.name | string | yes | URL slug of the repository - the :name segment of every repository route. |
repo.displayName | string | yes | Human-readable repository name. |
repo.description | string or null | yes | Free-text description, or null when the repository has none. |
repo.isPrivate | boolean | yes | True when the repository is private (visible to authorized users only). |
repo.defaultBranch | string | yes | Name of the default branch. |
repo.createdAt | string | yes | Creation timestamp, ISO 8601. |
repo.updatedAt | string | yes | Last-modification timestamp, ISO 8601. |
error | object | no | Why this item failed - absent when the item succeeded. |
Example request
curl -X POST https://<INSTANCE>.git.eu/api/v0/repos/batch \
-H "Authorization: Bearer giteu_your_token" \
-H "Content-Type: application/json" \
-d '{"repos":[{"displayName":"string"}]}'
Errors
| Type | Status | Title |
|---|---|---|
unauthorized | 401 | Unauthorized |
insufficient_scope | 403 | Insufficient scope |
validation_failed | 400 | Validation Failed |
Per-item errors
These never change the response status: they are carried by a failed item inside an otherwise successful 200 response.
| Type | Status | Title |
|---|---|---|
email_not_verified | 403 | Email not verified |
slug_taken | 409 | Slug already taken |
invalid_slug | 400 | Invalid repository name |
invalid_branch | 400 | Invalid branch name |
invalid_description | 400 | Invalid description |
gb_repo_exists | 409 | Repository already exists |
repo_locked | 423 | Repository locked |
gb_unavailable | 503 | Repository storage unavailable |
GET /api/v0/repos
Lists every repository owned by the calling token's user, optionally sorted and filtered. There is no pagination: the full owned list is returned.
| Property | Value |
|---|---|
| Access | Caller-scoped: the route only ever touches repositories owned by the token holder, so no per-repository access decision is made. |
| Success status | 200 |
| Success body | The standard JSON envelope, payload in data. |
Query parameters
Optional sort/filter of the returned list. There is no pagination.
| Field | Type | Required | Description |
|---|---|---|---|
sort | string | no | Sort token: name-asc, name-desc, created-desc or created-asc. Omitted or unrecognized: the default order applies (the value is ignored, never rejected). |
filter | string | no | Case-insensitive free-text needle matched against the repository name. Omitted or empty: no filtering. |
Response payload
The envelope's data member is an array; each element carries:
| Field | Type | Required | Description |
|---|---|---|---|
owner | string | yes | Username of the repository owner (the bearer token's user). |
name | string | yes | URL slug of the repository - the :name segment of every repository route. |
displayName | string | yes | Human-readable repository name. |
description | string or null | yes | Free-text description, or null when the repository has none. |
isPrivate | boolean | yes | True when the repository is private (visible to authorized users only). |
defaultBranch | string | yes | Name of the default branch. |
createdAt | string | yes | Creation timestamp, ISO 8601. |
updatedAt | string | yes | Last-modification timestamp, ISO 8601. |
Example request
curl -X GET https://<INSTANCE>.git.eu/api/v0/repos \
-H "Authorization: Bearer giteu_your_token"
Errors
| Type | Status | Title |
|---|---|---|
unauthorized | 401 | Unauthorized |
insufficient_scope | 403 | Insufficient scope |
validation_failed | 400 | Validation Failed |
GET /api/v0/repos/:owner/:name
Returns a single repository. A repository the caller may not read is reported as not found, never as a distinguishable access error.
| Property | Value |
|---|---|
| Access | Read access to the target repository. |
| Success status | 200 |
| Success body | The standard JSON envelope, payload in data. |
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
owner | string (6-42 chars) | yes | Username of the repository owner. Letters, digits, ., _, -; starts and ends with a letter or digit; no two of ._- in a row; may not end in .git, .atom or .html; 6-42 characters. |
name | string (1-128 chars) | yes | URL slug of the repository. Letters, digits, ., _, -; starts and ends with a letter or digit; no two of ._- in a row; may not end in .git, .atom or .html; 1-128 characters. |
Response payload
The envelope's data member carries:
| Field | Type | Required | Description |
|---|---|---|---|
owner | string | yes | Username of the repository owner (the bearer token's user). |
name | string | yes | URL slug of the repository - the :name segment of every repository route. |
displayName | string | yes | Human-readable repository name. |
description | string or null | yes | Free-text description, or null when the repository has none. |
isPrivate | boolean | yes | True when the repository is private (visible to authorized users only). |
defaultBranch | string | yes | Name of the default branch. |
createdAt | string | yes | Creation timestamp, ISO 8601. |
updatedAt | string | yes | Last-modification timestamp, ISO 8601. |
Example request
curl -X GET https://<INSTANCE>.git.eu/api/v0/repos/<USERNAME>/{name} \
-H "Authorization: Bearer giteu_your_token"
Errors
| Type | Status | Title |
|---|---|---|
unauthorized | 401 | Unauthorized |
insufficient_scope | 403 | Insufficient scope |
not_found | 404 | Not Found |
forbidden | 403 | Forbidden |
access_locked | 423 | Repository access locked |
access_frozen | 503 | Repository access temporarily frozen |
validation_failed | 400 | Validation Failed |
PATCH /api/v0/repos/:owner/:name
Updates a repository. Only the fields present in the body change; an absent field is left untouched, and no account default is ever merged in on update.
| Property | Value |
|---|---|
| Access | Administrative access to the target repository. |
| Success status | 200 |
| Success body | The standard JSON envelope, payload in data. |
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
owner | string (6-42 chars) | yes | Username of the repository owner. Letters, digits, ., _, -; starts and ends with a letter or digit; no two of ._- in a row; may not end in .git, .atom or .html; 6-42 characters. |
name | string (1-128 chars) | yes | URL slug of the repository. Letters, digits, ., _, -; starts and ends with a letter or digit; no two of ._- in a row; may not end in .git, .atom or .html; 1-128 characters. |
Request body
The repository fields to change. Every field is optional; an absent field is left unchanged, and no account default is ever merged in on update.
| Field | Type | Required | Description |
|---|---|---|---|
displayName | string (1-128 chars) | no | New human-readable repository name. Absent: unchanged. |
slug | string (1-128 chars) | no | New URL slug. Absent: unchanged. Changing it changes every URL of the repository. Letters, digits, ., _, -; starts and ends with a letter or digit; no two of ._- in a row; may not end in .git, .atom or .html; 1-128 characters. |
description | string (max 500 chars) | no | New free-text description. Absent: unchanged. |
isPrivate | boolean | no | New visibility - true for private. Absent: unchanged. |
Response payload
The envelope's data member carries:
| Field | Type | Required | Description |
|---|---|---|---|
owner | string | yes | Username of the repository owner (the bearer token's user). |
name | string | yes | URL slug of the repository - the :name segment of every repository route. |
displayName | string | yes | Human-readable repository name. |
description | string or null | yes | Free-text description, or null when the repository has none. |
isPrivate | boolean | yes | True when the repository is private (visible to authorized users only). |
defaultBranch | string | yes | Name of the default branch. |
createdAt | string | yes | Creation timestamp, ISO 8601. |
updatedAt | string | yes | Last-modification timestamp, ISO 8601. |
Example request
curl -X PATCH https://<INSTANCE>.git.eu/api/v0/repos/<USERNAME>/{name} \
-H "Authorization: Bearer giteu_your_token" \
-H "Content-Type: application/json" \
-d '{"displayName":"string"}'
Errors
| Type | Status | Title |
|---|---|---|
unauthorized | 401 | Unauthorized |
insufficient_scope | 403 | Insufficient scope |
not_found | 404 | Not Found |
forbidden | 403 | Forbidden |
access_locked | 423 | Repository access locked |
access_frozen | 503 | Repository access temporarily frozen |
email_not_verified | 403 | Email not verified |
validation_failed | 400 | Validation Failed |
slug_taken | 409 | Slug already taken |
invalid_slug | 400 | Invalid repository name |
invalid_description | 400 | Invalid description |
DELETE /api/v0/repos/:owner/:name
Permanently deletes a repository and its git data. The deletion is hard and cannot be undone. A successful call returns 204 with an empty body.
| Property | Value |
|---|---|
| Access | Ownership of the target repository. |
| Success status | 204 |
| Success body | Empty - this route returns no body. |
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
owner | string (6-42 chars) | yes | Username of the repository owner. Letters, digits, ., _, -; starts and ends with a letter or digit; no two of ._- in a row; may not end in .git, .atom or .html; 6-42 characters. |
name | string (1-128 chars) | yes | URL slug of the repository. Letters, digits, ., _, -; starts and ends with a letter or digit; no two of ._- in a row; may not end in .git, .atom or .html; 1-128 characters. |
Example request
curl -X DELETE https://<INSTANCE>.git.eu/api/v0/repos/<USERNAME>/{name} \
-H "Authorization: Bearer giteu_your_token"
Errors
| Type | Status | Title |
|---|---|---|
unauthorized | 401 | Unauthorized |
insufficient_scope | 403 | Insufficient scope |
not_found | 404 | Not Found |
forbidden | 403 | Forbidden |
access_locked | 423 | Repository access locked |
access_frozen | 503 | Repository access temporarily frozen |
email_not_verified | 403 | Email not verified |
validation_failed | 400 | Validation Failed |
repo_busy | 409 | Repository busy |
repo_locked | 423 | Repository locked |
gb_unavailable | 503 | Repository storage unavailable |
Errors
An error body carries an error object in the envelope's error member, served as application/problem+json (the standard problem format, RFC 9457).
| Field | Type | Required | Description |
|---|---|---|---|
type | string | yes | Machine-readable problem type - the stable value to branch on. Never parse the title. |
title | string | yes | Short human-readable summary, localized. |
status | number | yes | HTTP status code, repeated inside the body. |
detail | string | no | Human-readable explanation of this specific occurrence. |
instance | string | no | URI of the specific occurrence. |
extensions | object | no | Problem-specific extra members. |
Problem Types
Every problem type this API can return, response-level and per-item alike:
| Type | Status | Title |
|---|---|---|
unauthorized | 401 | Unauthorized |
insufficient_scope | 403 | Insufficient scope |
validation_failed | 400 | Validation Failed |
email_not_verified | 403 | Email not verified |
slug_taken | 409 | Slug already taken |
invalid_slug | 400 | Invalid repository name |
invalid_branch | 400 | Invalid branch name |
invalid_description | 400 | Invalid description |
gb_repo_exists | 409 | Repository already exists |
repo_locked | 423 | Repository locked |
gb_unavailable | 503 | Repository storage unavailable |
not_found | 404 | Not Found |
forbidden | 403 | Forbidden |
access_locked | 423 | Repository access locked |
access_frozen | 503 | Repository access temporarily frozen |
repo_busy | 409 | Repository busy |