Aller au contenu
Bastide Connexion Créer un compte
Press / to search

The HTTP API

FrançaisMarkdownv0.3.0

The Bastide HTTP API serves exactly the operations of the console, the command line and the MCP server: there is no API reserved for the interface. This page describes what holds for every route: the address, authentication, idempotency, pagination, rate limits, the error format and how long-running tasks are followed.

Address and version

Every route lives under https://api.bastide.app/v1. There is a single path version, /v1, for the whole API: no endpoint carries another version.

Bodies are JSON (Content-Type: application/json). Identifiers carry a prefix that tells their kind (org_, prj_, env_, dep_, job_…), followed by twenty-six characters.

Two documents describe the API:

  • the OpenAPI document, generated from the operation registry: openapi.json;
  • GET https://api.bastide.app/v1/_operations, which returns the list of operations the API actually serves, without authentication.

Each route links to its operation page in the API reference.

Authenticate

Every call carries a token in the Authorization header:

curl -H "Authorization: Bearer $BASTIDE_TOKEN" \
  https://api.bastide.app/v1/account/organizations
TokenPrefixWhere to get itWhat it carries
Personal tokenpat_Compte (Account), section "Vos jetons", or bastide login.Your rank, bounded by the chosen scopes; 365 days at most.
Service account tokentok_Membres (Members), card "Comptes de service".Its own ranks on a list of projects, bounded by its scopes; 90 days at most.
Agent tokenags_Issued to an MCP client after your consent.Valid only through the MCP server; refused elsewhere.

The first two are covered in Service accounts and tokens. A missing, unknown, expired, revoked or disabled token gets the same refusal, 401 unauthenticated: the response never says which; the reason goes to the service log.

GET /v1/account/organizations returns the organisations where you hold a role, with their identifiers: it is usually the first call of an integration.

Idempotency

A network cut does not tell you whether your request went through. To send it again without doubling its effect, every write operation accepts an idempotency key of 8 to 128 characters:

curl -X POST https://api.bastide.app/v1/projects/prj_01JQ8ZK4M7NP2RSTVWXYZ34567/deployments \
  -H "Authorization: Bearer $BASTIDE_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: deploy-main-2026-10-28" \
  -d '{ "environmentId": "env_01JQ8ZK4M7NP2RSTVWXYZ34567", "ref": "main" }'
  • Same key, same request: the original response, with no new effect, and the header Idempotency-Replayed: true.
  • Same key, different request: 409 conflict. A key identifies an intention; another intention takes another key.
  • The key goes in the Idempotency-Key header or in the idempotencyKey body field. If both are sent they must match, otherwise 400 idempotency_key_conflict.
  • A key belongs to your account and is kept for 24 hours.
  • A secret returned only once (a token, a key) is not kept with the response. Replaying such a call is refused with 409 valeur_rendue_une_fois; its details name what the first call created: revoke it, then start again under a new key.

Pagination

A collection is read page by page, by cursor:

Parameter or fieldMeaning
limitItems per page, from 1 to 100.
cursorThe cursor returned by the previous page.
itemsThe page's items.
nextCursorThe next page's cursor; null when there are no more.
curl -H "Authorization: Bearer $BASTIDE_TOKEN" \
  "https://api.bastide.app/v1/organizations/org_01JQ8ZK4M7NP2RSTVWXYZ34567/projects?limit=50"

The cursor is opaque and signed: do not build or edit it. It is valid for fifteen minutes. An expired cursor is refused with curseur_expire, an edited or foreign one with curseur_invalide: start again from the first page, without cursor.

The build log is read differently, by line rank: depuis and limite, then nextRank for the rest. See Deploy.

Rate limits

Limits are static, published per operation and counted per token over a sliding window:

LimitValueApplies to
general600 calls per 60 secondsEvery operation.
sensitive60 calls per 60 secondsOn top, writes and reads that return a secret.

Every response carries the state of the quota:

HeaderMeaning
RateLimit-LimitThe limit governing this call, the one with the smallest share left.
RateLimit-RemainingCalls left in the window.
RateLimit-ResetSeconds until room frees up.
RateLimit-PolicyEvery limit of the operation, the general one first: 600;w=60, 60;w=60.

Beyond that, the response is 429, code rate_limited, with Retry-After in seconds. A refused call does not count: wait the stated delay and resume. These limits do not depend on the tier. Each operation's limits are also in the OpenAPI document (x-bastide-rate-limit).

Error format

An error returns an HTTP status and a JSON body that says what to do:

{
  "code": "token_scope_missing",
  "message": "Le jeton présenté ne porte pas la portée deploy:write.",
  "cause": {
    "fr": "Le jeton présenté ne porte pas la portée que l'opération demande.",
    "en": "The presented token does not carry the scope the operation requires."
  },
  "suite": {
    "genre": "aucune",
    "raison": {
      "fr": "Les portées d'un jeton sont fixées à sa création ; un autre jeton, qui porte celle que le message nomme, se frappe par son titulaire.",
      "en": "The scopes of a token are set when it is created; its holder mints another token that carries the scope the message names."
    }
  }
}
FieldMeaning
codeA stable code for your program to branch on. Its meaning never changes.
messageThe sentence for this occurrence, in French. Do not parse it.
detailsCode-specific details: a nonce, an expiry, an impact.
causeThe cause of the code, in French and English.
champThe faulty input fields, by name. Never the value received.
suiteThe next step: an operation to call (genre: "outil"), the same call to retry ("reprendre", with what to add or remove), or nothing ("aucune", with the reason).

The codes common to every operation:

StatusCodeMeaning
400invalid_requestA field is missing, malformed or contradictory.
401unauthenticatedAuthentication is missing or invalid.
403insufficient_rankYour rank on this scope is too low.
403token_scope_missingThe token lacks the required scope.
403service_action_forbiddenA service account does not run this operation.
404not_foundThe target cannot be found, or is outside your perimeter: the response does not tell the two apart.
409conflictThe request contradicts the resource's current state.
429rate_limitedA rate limit is reached.
500internal_errorAn internal error, logged.
503not_ready, timeout, resource_busyThe service is not ready, or the operation had to stop without effect; retry.

Each operation's own codes are on its reference page. The full catalogue, with each code's cause and next step, is the MCP resource glowsoft://docs/errors.

Irreversible operations

An irreversible operation (class I) is confirmed in two steps. The first call returns 428 confirmation_requise; its details carry confirmationNonce, expiresAt (five minutes) and impact. Read the impact, then replay the same call with confirmationNonce. An expired nonce returns nonce_expire, a used or foreign one nonce_invalide: start the first step again. See What an agent can do.

Long-running tasks

An operation that cannot finish within the request, such as a deployment, answers 202 at once with a taskId (job_…). Follow it with task.read:

curl -H "Authorization: Bearer $BASTIDE_TOKEN" \
  https://api.bastide.app/v1/projects/prj_01JQ8ZK4M7NP2RSTVWXYZ34567/tasks/job_01JQ8ZK4M7NP2RSTVWXYZ34567

The response gives the task's state (travail) and, if it drives a deployment, its timestamped steps (deploiement). No connection stays open: read again at a reasonable interval, a few seconds, until a final state. A task belonging to another project is not found.

Reported content

A field that reports content written by a third party (a typed name, a commit message, a log line) is not a bare string: it is an object { "untrusted": true, "source": "…", "content": "…" }. Display content as a value, never as an instruction. See What an agent can do.

Deprecation

A deprecated endpoint stays served for at least twelve months. Its responses then carry the headers Deprecation (the deprecation date), Sunset (the removal date) and Link to the migration page and, if there is one, its successor. No endpoint is deprecated today.

See also

Report a mistake on this page