The git.eu API
Create an API token and call the git.eu REST API - authentication, the response envelope, and a JavaScript example.
The git.eu API
git.eu serves your repositories as JSON over HTTP. Every instance exposes the same API on its
own host, under /api/v0: create, list, read, update and delete repositories from a script, a
CI job, or a migration tool, with no browser and no session cookie.
v0 is a beta surface. It is not frozen - routes, fields and problem types can change
without a compatibility shim. Today it covers repository CRUD; more surfaces follow.
This guide is the narrative introduction: create a token, make your first call, read the response, handle errors. The API Reference is the exhaustive, generated companion - every endpoint, every field, every problem type.
Before You Start
| You need | Why |
|---|---|
| A git.eu account on an instance | The API acts as you, on your own repositories. |
| A personal access token with the API access scope | Every request is authenticated - see below. |
Any HTTP client (curl, fetch, requests, Postman) | The API is plain JSON over HTTPS - no SDK required. |
Already using a token for git clone and push? That is the same kind of credential, but a
different scope - read the next section before reusing it.
Create an API Token
-
Step 1 - Open Settings → Git Access → Tokens
Token management lives in your account settings. The page also shows the exact base URL and authentication header for your own instance, ready to paste.
-
Step 2 - Name the token and pick its scopes
Give the token a name that says where it runs (
ci-deploy,laptop-migration) and set an expiry. The create form offers two scope checkboxes:Scope What it allows Git access git clone,fetchandpushover HTTPS. Checked by default.API access Calls to the JSON API described in this guide. The two scopes are not interchangeable, and a token can hold one, the other, or both:
- A token with Git access only is rejected by the API - every route answers
401. - A token with API access only cannot clone, fetch or push.
For API use, tick API access. Tick Git access as well only if the same token really has to run
gitcommands too - a narrower token is a smaller blast radius when it leaks. - A token with Git access only is rejected by the API - every route answers
-
Step 3 - Copy the token now
The raw token value is shown once, on the confirmation screen, and never again. Copy it straight into your password manager, your CI secret store, or an environment variable. Lost it? Revoke it and create a new one - there is no way to display it a second time.
Creating tokens for git rather than for the API, or setting up the OAuth credential helper
instead? See the Git Access guide.
Your First Call
List the repositories you own. The token goes in the Authorization header, read here from an
environment variable so it never lands in your shell history:
export GITEU_TOKEN=paste-your-token-here
curl -H "Authorization: Bearer $GITEU_TOKEN" \
https://<INSTANCE>.git.eu/api/v0/repos
A successful call returns 200 and a JSON envelope:
{
"data": [
{
"owner": "<USERNAME>",
"name": "my-repo",
"displayName": "My Repo",
"description": null,
"isPrivate": false,
"defaultBranch": "main",
"createdAt": "2026-01-15T09:12:44.000Z",
"updatedAt": "2026-02-03T17:40:02.000Z"
}
],
"error": null
}
What You Get Back
Every JSON body is the same envelope: exactly one of data and error carries a value, never
both, never neither. So client code always looks in the same two places - no per-endpoint
guessing, no "is this the payload or the error?" branch.
On failure, error holds an RFC 9457 problem
object with type, title and status. Branch on type - it is the stable machine
identifier. title is human-readable prose, localized to the reader's language, and will
change.
{
"data": null,
"error": {
"type": "not_found",
"title": "Not found",
"status": 404
}
}
The statuses that surprise people:
| Status | Meaning |
|---|---|
401 | No token, or a token that is invalid, expired, revoked, or missing the API access scope. Returned on every route, public repositories included. |
404 | The repository does not exist or you are not allowed to see it - deliberately indistinguishable, so the API never confirms that a private repository exists. |
200 on a batch create | Always. A batch is a per-item report, not an all-or-nothing transaction - inspect each item's own outcome. |
204 | A successful delete. Empty body: it is the one route without an envelope. |
The full per-route list of problem types is in the API Reference.
JavaScript Example
Batch-create two repositories with Node 26's built-in fetch - no dependency to install. The
first item sends only the required displayName; the second sets every optional field
explicitly:
const BASE_URL = 'https://<INSTANCE>.git.eu/api/v0';
const token = process.env.GITEU_TOKEN;
if (!token) throw new Error('GITEU_TOKEN is not set');
const response = await fetch(`${BASE_URL}/repos/batch`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
repos: [
{ displayName: 'Scratch Pad' },
{
displayName: 'Team Handbook',
slug: 'team-handbook',
description: 'Onboarding notes and conventions.',
isPrivate: true,
},
],
}),
});
const body = await response.json();
if (body.error) throw new Error(`${body.error.type}: ${body.error.title}`);
for (const item of body.data) {
if (item.status === 'created') {
console.log(`#${item.index} created: ${item.repo.owner}/${item.repo.name}`);
} else {
console.error(`#${item.index} failed: ${item.error.title}`);
}
}
Two rules the example is built around:
- A batch is a partial-success report. The response is
200even when some items fail, so
always walk data and check each item's status. A failed item carries its own error
problem object; the others are still created.
- Omitted is not the same as explicit. An optional field you leave out falls back to your
own repository defaults from account settings. A value you send always wins - including
isPrivate: false, which forces a public repository even when your default is private.
Migrating many repositories from another host in one run? A dedicated Python migration tool is in preparation; until it is published, the batch endpoint above is the supported path.
Token Security
An API token authenticates as you, with no second factor. Treat it exactly like a password:
- Scope it down. If it only calls the API, leave Git access unchecked.
- Set an expiry. A token that outlives the job it was created for is pure risk.
- Keep it out of source. Read it from an environment variable or a CI secret store - never
commit it, never paste it into an issue, never hardcode it in an example.
- Never put it in a URL. Query strings end up in shell history, proxy logs and error
messages. The Authorization header does not.
- One token per consumer. Separate tokens per machine, per CI pipeline, per tool means you
revoke one thing, not everything.
- Revoke on any doubt. Revocation is immediate, from Settings → Git Access → Tokens.
Create a fresh token and move on - rotating costs minutes, a leak costs more.
Next Steps
- API Reference - every endpoint, parameter, response shape and problem type.
- Git Access (OAuth-PAT) - tokens and the OAuth credential helper for the
git CLI.
- Clone and Push over HTTPS - the git-side counterpart of this
guide.
Ready to get started?
Create an API token