Documentation
Documentation/Integrations

Référence API

Schémas publics des endpoints, authentification, scopes et exemples de requêtes.

APIRESTHTTP
Voir le Markdown
Sur cette page
Ouvrir l’explorateur API authentifié pour envoyer des requêtes

Les descriptions des endpoints et les noms des schémas sont communs aux deux langues.

Health & Workers

Service health checks and connected worker status monitoring.

GET/healthHealth checkSans authentification

Returns a plain-text OK response. Use this to verify the backend is running and reachable.

Authentification: none · Scopes: —

# GET /health

Corps de réponse

ChampType / statutObligatoireDescription
bodystringObligatoirePlain-text "ok" response.

Types de contenu: application/json → application/json

Exemple cURL

curl http://localhost:8080/health

Exemple de réponse

"ok"
GET/api/workers/statusGet connected workersJeton utilisateur

Returns project-scoped worker availability. Busy workers are only included when they are running an execution for the requested project; idle workers are anonymized.

Authentification: jwt_only · Scopes: read

# GET /api/workers/status

Paramètres de requête

ChampType / statutObligatoireDescription
project_iduuidObligatoireProject whose worker availability should be returned.

Corps de réponse

ChampType / statutObligatoireDescription
connectednumberObligatoireNumber of workers visible for the requested project.
workersWorkerInfo[]ObligatoireArray of project-visible worker details.
workers[].worker_idstringObligatoireUnique worker identifier for project-busy workers, or an anonymized availability identifier for idle workers.
workers[].statusstringObligatoireWorker status: "idle" or "busy".
workers[].connected_atstringFacultatifISO 8601 timestamp of connection time for project-busy workers.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  "http://localhost:8080/api/workers/status?project_id=PROJECT_ID"

Exemple de réponse

{
  "connected": 2,
  "workers": [
    {
      "worker_id": "available-1",
      "worker_name": "Available worker",
      "status": "idle"
    },
    {
      "worker_id": "worker-2",
      "worker_name": "Project worker",
      "status": "busy",
      "connected_at": "2026-04-04T09:45:00Z"
    }
  ]
}

Workspaces

Manage workspaces. Users can start with no workspaces; each workspace owns its projects and workers.

GET/api/workspacesList workspacesJeton utilisateur

Returns workspace_members rows for the authenticated user, with each workspace embedded under the workspaces field.

Authentification: jwt_only · Scopes: read

# GET /api/workspaces

Corps de réponse

ChampType / statutObligatoireDescription
workspace_idstringObligatoireWorkspace UUID from workspace_members.
rolestringObligatoireUser role in the workspace.
workspacesobjectObligatoireEmbedded workspace: id, name, slug, plan, max_concurrent_executions, created_at.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/workspaces

Exemple de réponse

[
  {
    "workspace_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "role": "owner",
    "workspaces": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "Acme Corp",
      "slug": "acme-corp",
      "plan": "free",
      "max_concurrent_executions": 10,
      "created_at": "2026-01-15T08:30:00Z"
    }
  }
]
POST/api/workspacesCreate workspaceJeton utilisateur

Creates a new workspace, inserts the caller as owner, and optionally sets an workspace execution concurrency limit.

Authentification: jwt_only · Scopes: write

# POST /api/workspaces

Corps de requête

ChampType / statutObligatoireDescription
namestringObligatoireDisplay name for the new workspace.
max_concurrent_executionsnumberFacultatifOptional workspace-wide running execution limit.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireUUID of the newly created workspace.
namestringObligatoireWorkspace name.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"New Workspace","max_concurrent_executions":5}' \
  http://localhost:8080/api/workspaces

Exemple de réponse

{
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "name": "New Workspace",
  "slug": "new-workspace-1a2b3c4d",
  "plan": "free",
  "max_concurrent_executions": 5,
  "created_at": "2026-04-04T12:00:00Z"
}
PUT/api/workspaces/{workspaceId}Update workspaceJeton utilisateur

Updates workspace metadata and workspace-wide execution concurrency for an owner/admin JWT session.

Authentification: jwt_only · Scopes: write

# PUT /api/workspaces/{workspaceId}

Paramètres de chemin

ChampType / statutObligatoireDescription
workspaceIdstringObligatoireUUID of the workspace.

Corps de requête

ChampType / statutObligatoireDescription
namestringFacultatifNew display name.
max_concurrent_executionsnumberFacultatifWorkspace-wide running execution limit.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireWorkspace UUID.
namestringObligatoireWorkspace name.
max_concurrent_executionsnumberObligatoireWorkspace-wide running execution limit.

Types de contenu: application/json → application/json

Exemple cURL

curl -X PUT -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"max_concurrent_executions":5}' \
  http://localhost:8080/api/workspaces/b2c3d4e5-f6a7-8901-bcde-f12345678901

Exemple de réponse

[
  {
    "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "name": "New Workspace",
    "max_concurrent_executions": 5
  }
]
GET/api/workspaces/{workspaceId}/statsGet workspace statsJeton utilisateur

Returns aggregate execution and job stats across all projects in a workspace.

Authentification: jwt_only · Scopes: read

# GET /api/workspaces/{workspaceId}/stats

Paramètres de chemin

ChampType / statutObligatoireDescription
workspaceIdstringObligatoireUUID of the workspace.

Corps de réponse

ChampType / statutObligatoireDescription
project_countnumberObligatoireProjects in the workspace.
total_runsnumberObligatoireTotal executions.
passednumberObligatoirePassed executions.
failednumberObligatoireFailed executions.
errorsnumberObligatoireErrored executions.
runningnumberObligatoireRunning or pending executions.
avg_duration_msnumberObligatoireAverage completed run duration.
last_run_atstring | nullObligatoireMost recent execution creation time.
pass_ratenumberObligatoirePass percentage across terminal runs.
job_countnumberObligatoireSaved jobs in the workspace.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/workspaces/b2c3d4e5-f6a7-8901-bcde-f12345678901/stats

Exemple de réponse

{
  "project_count": 3,
  "total_runs": 128,
  "passed": 118,
  "failed": 7,
  "errors": 3,
  "running": 1,
  "avg_duration_ms": 2410,
  "last_run_at": "2026-05-02T15:30:00Z",
  "pass_rate": 92.2,
  "job_count": 14
}
GET/api/workspaces/{workspaceId}/project-healthGet workspace project healthJeton utilisateur

Returns the latest 12 execution outcomes and current active-run count for every project the authenticated workspace member can access.

Authentification: jwt_only · Scopes: read

# GET /api/workspaces/{workspaceId}/project-health

Paramètres de chemin

ChampType / statutObligatoireDescription
workspaceIdstringObligatoireUUID of the workspace.

Corps de réponse

ChampType / statutObligatoireDescription
project_idstringObligatoireAccessible project UUID.
recent_runsarrayObligatoireUp to 12 recent status and creation-time records, oldest first.
recent_pass_ratenumberObligatoirePass percentage across recent terminal runs.
runningnumberObligatoireAll currently pending or running executions.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/workspaces/b2c3d4e5-f6a7-8901-bcde-f12345678901/project-health

Exemple de réponse

[
  {
    "project_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "recent_runs": [
      {
        "status": "failed",
        "created_at": "2026-08-19T10:00:00Z"
      },
      {
        "status": "passed",
        "created_at": "2026-08-19T11:00:00Z"
      }
    ],
    "recent_pass_rate": 50,
    "running": 0
  }
]

Projects

Manage projects within workspaces. Projects group jobs, test runs, triggers, and queues.

GET/api/workspaces/{workspaceId}/projectsList workspace projectsJeton utilisateur

Returns all projects in the workspace for a browser-authenticated workspace member.

Authentification: jwt_only · Scopes: —

# GET /api/workspaces/{workspaceId}/projects

Paramètres de chemin

ChampType / statutObligatoireDescription
workspaceIdstringObligatoireUUID of the workspace.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireProject UUID.
namestringObligatoireProject name.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/projects

Exemple de réponse

[
  {
    "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "name": "Website QA",
    "created_at": "2026-02-01T09:00:00Z"
  }
]
POST/api/workspaces/{workspaceId}/projectsCreate projectJeton utilisateur

Creates a new project within the specified workspace for an owner/admin JWT session.

Authentification: jwt_only · Scopes: —

# POST /api/workspaces/{workspaceId}/projects

Paramètres de chemin

ChampType / statutObligatoireDescription
workspaceIdstringObligatoireUUID of the workspace.

Corps de requête

ChampType / statutObligatoireDescription
namestringObligatoireProject name.
max_concurrent_executionsnumberFacultatifOptional project-level running execution limit.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireUUID of the newly created project.
namestringObligatoireProject name.
workspace_idstringObligatoireUUID of the owning workspace.
max_concurrent_executionsnumber | nullFacultatifProject-level running execution limit, if set.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Checkout Flow RPA","max_concurrent_executions":3}' \
  http://localhost:8080/api/workspaces/a1b2c3d4-e5f6-7890-abcd-ef1234567890/projects

Exemple de réponse

[
  {
    "id": "d4e5f6a7-b8c9-0123-defa-234567890123",
    "workspace_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "Checkout Flow RPA",
    "max_concurrent_executions": 3,
    "created_at": "2026-04-04T12:30:00Z"
  }
]
GET/api/projectsList all user projectsJeton utilisateur ou clé API

Returns all projects the authenticated user has access to, across all workspaces.

Authentification: dual · Scopes: read

# GET /api/projects

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireProject UUID.
namestringObligatoireProject name.
project_typestringObligatoireProject type.
workspace_idstringObligatoireUUID of the owning workspace.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/projects

Exemple de réponse

[
  {
    "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "name": "Website QA",
    "project_type": "qa",
    "workspace_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "created_at": "2026-02-01T09:00:00Z"
  }
]
PUT/api/projects/{projectId}Update projectJeton utilisateur

Updates project metadata and clears or sets project-level execution concurrency for an owner/admin JWT session.

Authentification: jwt_only · Scopes: write

# PUT /api/projects/{projectId}

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de requête

ChampType / statutObligatoireDescription
namestringFacultatifNew project name.
max_concurrent_executionsnumber | nullFacultatifProject running execution limit, or null to inherit from the workspace.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireProject UUID.
namestringObligatoireProject name.
max_concurrent_executionsnumber | nullFacultatifProject-level running execution limit.

Types de contenu: application/json → application/json

Exemple cURL

curl -X PUT -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"max_concurrent_executions":null}' \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012

Exemple de réponse

[
  {
    "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "name": "Website QA",
    "max_concurrent_executions": null
  }
]

GitHub

Connect a project to a GitHub App installation, browse repository state, and export BernOps-managed tests as draft pull requests.

GET/api/github/setupComplete GitHub setupSans authentification

GitHub redirects to this endpoint during OAuth authorization and again after installation. It validates the signed setup state, verifies the installing user can access the returned installation, records the installation, and redirects back to the frontend project GitHub page.

Authentification: none · Scopes: —

# GET /api/github/setup

Paramètres de requête

ChampType / statutObligatoireDescription
statestringObligatoireSigned setup state returned by GitHub from the authorization or installation URL.
codestringFacultatifGitHub OAuth code returned before installation so BernOps can obtain a user access token for setup verification.
installation_idnumberFacultatifGitHub App installation ID assigned by GitHub after OAuth authorization completes.

Corps de réponse

ChampType / statutObligatoireDescription
LocationstringObligatoireFrontend redirect URL containing the setup result query parameters.

Types de contenu: application/json → application/json

Exemple cURL

# Browser redirect endpoint. Start setup through:
curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN"   http://localhost:8080/api/projects/PROJECT_ID/github/install-url

Exemple de réponse

HTTP/1.1 302 Found
Location: http://app.bernops-dev/projects/github?projectId=PROJECT_ID&github=installed
POST/api/github/webhooksReceive GitHub webhookSans authentification

Receives GitHub App webhook deliveries, validates the X-Hub-Signature-256 HMAC signature, deduplicates deliveries, and syncs installation, repository, and pull request state. Processing failures are recorded and returned as non-2xx responses so GitHub can retry.

Authentification: none · Scopes: —

# POST /api/github/webhooks

Corps de requête

ChampType / statutObligatoireDescription
payloadGitHub webhook JSONObligatoireRaw GitHub webhook payload. The exact shape depends on the X-GitHub-Event header.

Corps de réponse

ChampType / statutObligatoireDescription
acceptedbooleanObligatoireWhether the delivery was accepted for processing.
delivery_idstringObligatoireGitHub delivery ID from X-GitHub-Delivery.
statusstringFacultatifProcessing status recorded for the delivery.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "X-GitHub-Event: installation" \
  -H "X-GitHub-Delivery: delivery-001" \
  -H "X-Hub-Signature-256: sha256=CALCULATED_SIGNATURE" \
  -H "Content-Type: application/json" \
  -d '{"action":"created"}' \
  http://localhost:8080/api/github/webhooks

Exemple de réponse

{
  "accepted": true,
  "delivery_id": "delivery-001",
  "status": "processed"
}
POST/api/projects/{projectId}/github/install-urlCreate install URLJeton utilisateur

Creates a short-lived signed setup state and returns the GitHub App user authorization URL for a workspace owner/admin. The OAuth step is required before installation so BernOps can verify the returned installation belongs to the installing GitHub user.

Authentification: jwt_only · Scopes: —

# POST /api/projects/{projectId}/github/install-url

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project to connect.

Corps de réponse

ChampType / statutObligatoireDescription
urlstringObligatoireGitHub App user authorization URL containing the signed state.
expires_atstringObligatoireISO 8601 expiry timestamp for the setup state.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/projects/PROJECT_ID/github/install-url

Exemple de réponse

{
  "url": "https://github.com/login/oauth/authorize?client_id=Iv1.example&redirect_uri=https%3A%2F%2Fapi.bernops.example%2Fapi%2Fgithub%2Fsetup&state=SIGNED_STATE",
  "expires_at": "2026-05-03T12:10:00Z"
}
GET/api/projects/{projectId}/github/statusGet GitHub statusJeton utilisateur

Returns the project GitHub connection state, available workspace installations, selected repository, pull request sync state, whether the current user can manage the project connection, and whether they can install the workspace GitHub App.

Authentification: jwt_only · Scopes: —

# GET /api/projects/{projectId}/github/status

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
installedbooleanObligatoireWhether the workspace has at least one GitHub App installation.
connectedbooleanObligatoireWhether the project has a selected repository.
installationsGitHubInstallation[]ObligatoireWorkspace installations visible to the project.
repositoryGitHubRepository | nullFacultatifSelected project repository, if connected.
pull_requestsGitHubPullRequest[]ObligatoireTracked BernOps export pull requests for the selected repository.
can_managebooleanObligatoireWhether the current user can manage the GitHub connection.
can_installbooleanObligatoireWhether the current user can create workspace-level GitHub App install URLs.
default_folderstringObligatoireDefault folder used when selecting a repository.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/projects/PROJECT_ID/github/status

Exemple de réponse

{
  "installed": true,
  "connected": true,
  "installations": [
    {
      "id": "installation-001",
      "account_login": "acme"
    }
  ],
  "repository": {
    "repo_full_name": "acme/web",
    "html_url": "https://github.com/acme/web",
    "default_branch": "main",
    "test_folder_path": "bernops/e2e"
  },
  "pull_requests": [],
  "can_manage": true,
  "can_install": true,
  "default_folder": "bernops/e2e"
}
DELETE/api/projects/{projectId}/githubDisconnect repositoryJeton utilisateur

Disconnects the selected GitHub repository from a project. The workspace installation remains available for reconnecting this or another repository.

Authentification: jwt_only · Scopes: —

# DELETE /api/projects/{projectId}/github

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
installedbooleanObligatoireWhether a workspace installation remains available.
connectedbooleanObligatoireWhether the project still has a selected repository.
installationsGitHubInstallation[]ObligatoireWorkspace installations still available after disconnecting.
repositoryGitHubRepository | nullFacultatifSelected repository after disconnecting, normally null.
pull_requestsGitHubPullRequest[]ObligatoireTracked pull requests after disconnecting, normally empty.
can_managebooleanObligatoireWhether the current user can manage the GitHub connection.
can_installbooleanObligatoireWhether the current user can create workspace-level GitHub App install URLs.
default_folderstringObligatoireDefault export folder used by repository selection.

Types de contenu: application/json → application/json

Exemple cURL

curl -X DELETE -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/projects/PROJECT_ID/github

Exemple de réponse

{
  "installed": true,
  "connected": false,
  "repository": null,
  "pull_requests": []
}
GET/api/projects/{projectId}/github/reposList GitHub repositoriesJeton utilisateur

Lists repositories available through each workspace GitHub App installation so a project admin can select one for BernOps sync.

Authentification: jwt_only · Scopes: —

# GET /api/projects/{projectId}/github/repos

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
installationsArray<{ installation: GitHubInstallation; repositories: GitHubRepository[] }>ObligatoireRepositories grouped by installation.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/projects/PROJECT_ID/github/repos

Exemple de réponse

{
  "installations": [
    {
      "installation": {
        "id": "installation-001",
        "account_login": "acme"
      },
      "repositories": [
        {
          "id": 123,
          "full_name": "acme/web",
          "default_branch": "main"
        }
      ]
    }
  ]
}
POST/api/projects/{projectId}/github/repos/selectSelect repositoryJeton utilisateur

Connects a project to one repository exposed by a workspace GitHub App installation and stores the folder where BernOps-managed tests are exported.

Authentification: jwt_only · Scopes: —

# POST /api/projects/{projectId}/github/repos/select

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de requête

ChampType / statutObligatoireDescription
installation_idstringObligatoireBernOps installation row UUID returned by repository listing.
github_repo_idnumberObligatoireGitHub repository ID to connect.
test_folder_pathstringFacultatifRepository folder for BernOps test exports. Defaults to bernops/e2e.

Corps de réponse

ChampType / statutObligatoireDescription
connectedbooleanObligatoireWhether the project now has a selected repository.
installedbooleanObligatoireWhether the workspace has a GitHub App installation.
installationsGitHubInstallation[]ObligatoireWorkspace installations visible to the project.
repositoryGitHubRepositoryObligatoireStored repository connection.
pull_requestsGitHubPullRequest[]ObligatoireTracked BernOps pull requests for the selected repository.
can_managebooleanObligatoireWhether the current user can manage the GitHub connection.
can_installbooleanObligatoireWhether the current user can create workspace-level GitHub App install URLs.
default_folderstringObligatoireDefault export folder used by repository selection.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"installation_id":"installation-001","github_repo_id":123,"test_folder_path":"bernops/e2e"}' \
  http://localhost:8080/api/projects/PROJECT_ID/github/repos/select

Exemple de réponse

{
  "installed": true,
  "connected": true,
  "repository": {
    "repo_full_name": "acme/web",
    "html_url": "https://github.com/acme/web",
    "default_branch": "main",
    "test_folder_path": "bernops/e2e"
  }
}
GET/api/projects/{projectId}/github/treeGet repository treeJeton utilisateur

Reads the selected repository tree through the project GitHub App installation. Use recursive=true to request a recursive tree from GitHub.

Authentification: jwt_only · Scopes: —

# GET /api/projects/{projectId}/github/tree

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Paramètres de requête

ChampType / statutObligatoireDescription
refstringFacultatifBranch, tag, or SHA to read. Defaults to the selected repository default branch.
recursivebooleanFacultatifWhether GitHub should return the tree recursively.

Corps de réponse

ChampType / statutObligatoireDescription
shastringObligatoireTree SHA returned by GitHub.
entriesGitHubTreeEntry[]ObligatoireRepository tree entries.
truncatedbooleanFacultatifWhether GitHub truncated the tree response.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  "http://localhost:8080/api/projects/PROJECT_ID/github/tree?recursive=true"

Exemple de réponse

{
  "sha": "tree-sha",
  "entries": [
    {
      "path": "bernops/e2e/login.spec.ts",
      "type": "blob",
      "sha": "file-sha"
    }
  ],
  "truncated": false
}
POST/api/projects/{projectId}/github/export-testsExport tests to GitHubJeton utilisateur

Exports BernOps-managed tests to the selected repository, commits them to a BernOps branch, and opens or updates a draft pull request.

Authentification: jwt_only · Scopes: —

# POST /api/projects/{projectId}/github/export-tests

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
pull_requestGitHubPullRequestObligatoireCreated or updated GitHub pull request.
commitGitHubCommitObligatoireCommit created on the BernOps export branch.
exportedArray<{ job_id: string; path: string }>ObligatoireTests written to GitHub.
skippedArray<{ job_id: string; path?: string; reason: string }>ObligatoireTests skipped because they were empty, duplicated, or conflicted with remote content.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/projects/PROJECT_ID/github/export-tests

Exemple de réponse

{
  "pull_request": {
    "number": 42,
    "url": "https://github.com/acme/web/pull/42",
    "draft": true
  },
  "commit": {
    "branch_name": "bernops/update-tests-20260503121000-ab12cd34",
    "commit_sha": "commit-sha",
    "tree_sha": "tree-sha"
  },
  "exported": [
    {
      "job_id": "job-001",
      "path": "bernops/e2e/login.spec.ts"
    }
  ],
  "skipped": []
}
GET/api/projects/{projectId}/github/pull-requestsList export pull requestsJeton utilisateur

Returns BernOps-tracked GitHub export pull requests for the selected project repository.

Authentification: jwt_only · Scopes: —

# GET /api/projects/{projectId}/github/pull-requests

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
pull_requestsGitHubPullRequest[]ObligatoireTracked pull request records for the selected repository.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/projects/PROJECT_ID/github/pull-requests

Exemple de réponse

{
  "pull_requests": [
    {
      "branch_name": "bernops/update-tests-20260503121000-ab12cd34",
      "status": "open",
      "draft": true,
      "pr_number": 42,
      "pr_url": "https://github.com/acme/web/pull/42"
    }
  ]
}

Project Variables

Manage project runtime variables. Secret values are encrypted, write-only, and only injected into authorized executions.

GET/api/projects/{projectId}/variablesList project variablesJeton utilisateur

Returns variable metadata and plain non-secret values for a project. Secret values are never returned.

Authentification: jwt_only · Scopes: read

# GET /api/projects/{projectId}/variables

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireVariable UUID.
namestringObligatoireEnvironment variable name.
is_secretbooleanObligatoireWhether the value is encrypted and write-only.
valuestring | nullFacultatifPlain value for non-secret variables only.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/projects/project-001/variables

Exemple de réponse

[
  {
    "id": "var-001",
    "name": "BASE_URL",
    "is_secret": false,
    "value": "https://app.example.com"
  },
  {
    "id": "var-002",
    "name": "API_TOKEN",
    "is_secret": true,
    "value": null
  }
]
POST/api/projects/{projectId}/variablesCreate project variableJeton utilisateur

Creates a plain or secret runtime variable. Project admin access is required.

Authentification: jwt_only · Scopes: write

# POST /api/projects/{projectId}/variables

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de requête

ChampType / statutObligatoireDescription
namestringObligatoireUppercase env var name.
descriptionstringFacultatifOperator-facing description.
is_secretbooleanObligatoireEncrypt and hide the value after save.
valuestringObligatoireVariable value to store.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireVariable UUID.
namestringObligatoireEnvironment variable name.
is_secretbooleanObligatoireWhether the value is secret.
secret_versionnumberObligatoireSecret version counter.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"API_TOKEN","description":"CI token","is_secret":true,"value":"secret-value"}' \
  http://localhost:8080/api/projects/project-001/variables

Exemple de réponse

{
  "id": "var-002",
  "name": "API_TOKEN",
  "is_secret": true,
  "value": null,
  "secret_version": 1
}
PUT/api/project-variables/{variableId}Update project variableJeton utilisateur

Updates variable metadata or value. Updating a secret value increments its secret version.

Authentification: jwt_only · Scopes: write

# PUT /api/project-variables/{variableId}

Paramètres de chemin

ChampType / statutObligatoireDescription
variableIdstringObligatoireUUID of the variable.

Corps de requête

ChampType / statutObligatoireDescription
namestringFacultatifNew uppercase env var name.
descriptionstringFacultatifNew description.
valuestringFacultatifNew value.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireVariable UUID.
namestringObligatoireEnvironment variable name.
secret_versionnumberObligatoireSecret version counter.

Types de contenu: application/json → application/json

Exemple cURL

curl -X PUT -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"description":"Rotated token"}' \
  http://localhost:8080/api/project-variables/var-002

Exemple de réponse

{
  "id": "var-002",
  "name": "API_TOKEN",
  "is_secret": true,
  "value": null,
  "secret_version": 2
}
DELETE/api/project-variables/{variableId}Delete project variableJeton utilisateur

Deletes a project variable after project admin access checks.

Authentification: jwt_only · Scopes: write

# DELETE /api/project-variables/{variableId}

Paramètres de chemin

ChampType / statutObligatoireDescription
variableIdstringObligatoireUUID of the variable.

Corps de réponse

ChampType / statutObligatoireDescription
deletedbooleanObligatoireDeletion confirmation.

Types de contenu: application/json → application/json

Exemple cURL

curl -X DELETE -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/project-variables/var-002

Exemple de réponse

{
  "deleted": true
}
POST/api/project-variables/{variableId}/rotateRotate secret variableJeton utilisateur

Replaces the value for a secret variable and increments its version.

Authentification: jwt_only · Scopes: write

# POST /api/project-variables/{variableId}/rotate

Paramètres de chemin

ChampType / statutObligatoireDescription
variableIdstringObligatoireUUID of the secret variable.

Corps de requête

ChampType / statutObligatoireDescription
valuestringObligatoireNew secret value.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireVariable UUID.
secret_versionnumberObligatoireIncremented secret version.
last_rotated_atstringObligatoireRotation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value":"new-secret-value"}' \
  http://localhost:8080/api/project-variables/var-002/rotate

Exemple de réponse

{
  "id": "var-002",
  "name": "API_TOKEN",
  "is_secret": true,
  "value": null,
  "secret_version": 3
}

Jobs

Manage Playwright test jobs within a project. Jobs contain the test code that can be executed on demand or via triggers.

GET/api/projects/{projectId}/jobsList jobsJeton utilisateur ou clé API

Returns all jobs belonging to the specified project.

Authentification: dual · Scopes: jobs:read

# GET /api/projects/{projectId}/jobs

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireJob UUID.
namestringObligatoireJob display name.
descriptionstringFacultatifOptional description.
file_namestringFacultatifOriginal file name.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/jobs

Exemple de réponse

[
  {
    "id": "e5f6a7b8-c9d0-1234-efab-345678901234",
    "name": "Login Flow",
    "description": "Tests the sign-in flow end to end.",
    "file_name": "login.spec.ts",
    "created_at": "2026-03-10T14:00:00Z"
  }
]
POST/api/projects/{projectId}/jobsCreate jobJeton utilisateur ou clé API

Creates a new job within the specified project. Project API keys need jobs:write. The code field contains the Playwright test source.

Authentification: dual · Scopes: jobs:write

# POST /api/projects/{projectId}/jobs

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de requête

ChampType / statutObligatoireDescription
namestringObligatoireJob display name.
descriptionstringFacultatifOptional description of what the job tests.
codestringObligatoirePlaywright test source code.
file_namestringFacultatifOriginal file name (e.g. login.spec.ts).
max_concurrent_executionsnumber | nullFacultatifOptional per-job concurrency limit. Null inherits project and workspace limits.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireUUID of the newly created job.
namestringObligatoireJob name.
codestringObligatoireJob source code.
created_atstringObligatoireISO 8601 creation timestamp.
max_concurrent_executionsnumber | nullFacultatifPer-script concurrency limit, when configured.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name":"Login Flow","code":"import { test } from ...","file_name":"login.spec.ts","max_concurrent_executions":1}' \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/jobs

Exemple de réponse

{
  "id": "f6a7b8c9-d0e1-2345-fabc-456789012345",
  "name": "Login Flow",
  "code": "import { test } from '@playwright/test'; ...",
  "max_concurrent_executions": 1,
  "created_at": "2026-04-04T13:00:00Z"
}
GET/api/jobs/{jobId}Get jobJeton utilisateur ou clé API

Returns the full details of a single job, including its code.

Authentification: dual · Scopes: jobs:read

# GET /api/jobs/{jobId}

Paramètres de chemin

ChampType / statutObligatoireDescription
jobIdstringObligatoireUUID of the job.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireJob UUID.
namestringObligatoireJob name.
descriptionstringFacultatifOptional description.
codestringObligatoirePlaywright test source code.
file_namestringFacultatifOriginal file name.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/jobs/e5f6a7b8-c9d0-1234-efab-345678901234

Exemple de réponse

{
  "id": "e5f6a7b8-c9d0-1234-efab-345678901234",
  "name": "Login Flow",
  "description": "Tests the sign-in flow end to end.",
  "code": "import { test } from '@playwright/test'; ...",
  "file_name": "login.spec.ts",
  "created_at": "2026-03-10T14:00:00Z"
}
PUT/api/jobs/{jobId}Update jobJeton utilisateur ou clé API

Updates an existing job. Project API keys need jobs:write. All fields in the request body are optional; only provided fields are updated.

Authentification: dual · Scopes: jobs:write

# PUT /api/jobs/{jobId}

Paramètres de chemin

ChampType / statutObligatoireDescription
jobIdstringObligatoireUUID of the job.

Corps de requête

ChampType / statutObligatoireDescription
namestringFacultatifNew job name.
descriptionstringFacultatifNew description.
codestringFacultatifUpdated Playwright test source code.
file_namestringFacultatifUpdated file name.
max_concurrent_executionsnumber | nullFacultatifSet or clear the per-job concurrency limit.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireJob UUID.
namestringObligatoireUpdated job name.
codestringObligatoireUpdated source code.
max_concurrent_executionsnumber | nullFacultatifPer-script concurrency limit, when configured.
updated_atstringObligatoireISO 8601 update timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X PUT -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name":"Login Flow v2","code":"import { test } from ...","max_concurrent_executions":1}' \
  http://localhost:8080/api/jobs/e5f6a7b8-c9d0-1234-efab-345678901234

Exemple de réponse

{
  "id": "e5f6a7b8-c9d0-1234-efab-345678901234",
  "name": "Login Flow v2",
  "code": "import { test } from '@playwright/test'; ...",
  "max_concurrent_executions": 1,
  "updated_at": "2026-04-04T14:00:00Z"
}
DELETE/api/jobs/{jobId}Delete jobJeton utilisateur ou clé API

Permanently deletes a job and its association with triggers. Project API keys need jobs:write. Existing test run history is preserved.

Authentification: dual · Scopes: jobs:write

# DELETE /api/jobs/{jobId}

Paramètres de chemin

ChampType / statutObligatoireDescription
jobIdstringObligatoireUUID of the job to delete.

Corps de réponse

ChampType / statutObligatoireDescription
messagestringObligatoireConfirmation message.

Types de contenu: application/json → application/json

Exemple cURL

curl -X DELETE -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/jobs/e5f6a7b8-c9d0-1234-efab-345678901234

Exemple de réponse

{
  "message": "Job deleted successfully."
}
GET/api/jobs/{jobId}/runsList job runsJeton utilisateur ou clé API

Returns all test runs associated with a specific job, ordered by most recent first.

Authentification: dual · Scopes: runs:read

# GET /api/jobs/{jobId}/runs

Paramètres de chemin

ChampType / statutObligatoireDescription
jobIdstringObligatoireUUID of the job.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireTest run execution ID.
statusstringObligatoireRun status: "pending", "running", "passed", "failed", "cancelled".
started_atstringFacultatifISO 8601 start timestamp.
completed_atstringFacultatifISO 8601 completion timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/jobs/e5f6a7b8-c9d0-1234-efab-345678901234/runs

Exemple de réponse

[
  {
    "id": "run-001",
    "status": "passed",
    "started_at": "2026-04-04T10:00:00Z",
    "completed_at": "2026-04-04T10:02:30Z"
  }
]
POST/api/jobs/{jobId}/executeExecute jobJeton utilisateur ou clé API

Starts a test run from a saved job and dispatches it to an available worker. Project API keys need `jobs:execute`; keys with `variables:use` include secret project variables by default unless `include_secret_variables` is false. JWT callers only include secrets when `include_secret_variables` is explicitly true.

Authentification: dual · Scopes: jobs:execute

# POST /api/jobs/{jobId}/execute

Paramètres de chemin

ChampType / statutObligatoireDescription
jobIdstringObligatoireUUID of the saved job to execute.

Corps de requête

ChampType / statutObligatoireDescription
base_urlstringFacultatifBase URL override for this run.
include_secret_variablesbooleanFacultatifWhether to include secret project variables. Defaults to true for API keys with `variables:use`, false otherwise.

Corps de réponse

ChampType / statutObligatoireDescription
execution_idstringObligatoireUnique execution ID for this test run.
statusstringObligatoireInitial status, typically "pending" or "running".
worker_idstringFacultatifID of the assigned worker, if dispatched immediately.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"base_url":"https://staging.example.com"}' \
  http://localhost:8080/api/jobs/e5f6a7b8-c9d0-1234-efab-345678901234/execute

Exemple de réponse

{
  "execution_id": "exec-a1b2c3d4",
  "status": "running",
  "worker_id": "worker-1"
}
GET/api/jobs/{jobId}/statsGet job statsJeton utilisateur ou clé API

Returns aggregated statistics for a job: total runs, pass rate, average duration.

Authentification: dual · Scopes: jobs:read

# GET /api/jobs/{jobId}/stats

Paramètres de chemin

ChampType / statutObligatoireDescription
jobIdstringObligatoireUUID of the job.

Corps de réponse

ChampType / statutObligatoireDescription
total_runsnumberObligatoireTotal number of runs for this job.
pass_ratenumberObligatoirePercentage of passed runs (0-100).
avg_duration_msnumberObligatoireAverage run duration in milliseconds.
last_run_atstringFacultatifISO 8601 timestamp of the most recent run.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/jobs/e5f6a7b8-c9d0-1234-efab-345678901234/stats

Exemple de réponse

{
  "total_runs": 42,
  "pass_rate": 95.2,
  "avg_duration_ms": 15200,
  "last_run_at": "2026-04-04T10:02:30Z"
}

Test Runs

Execute and monitor Playwright test runs. Runs are dispatched to connected workers and stream logs and steps in real time.

POST/api/projects/{projectId}/test-runsStart test runJeton utilisateur ou clé API

Creates a new test run and dispatches it to an available worker. Provide `test_files` for an ad-hoc run or a `job_id` to execute a saved job.

Authentification: dual · Scopes: runs:write jobs:execute

# POST /api/projects/{projectId}/test-runs

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de requête

ChampType / statutObligatoireDescription
test_filesTestFile[]FacultatifInline Playwright files to execute. Each entry should include `file_name` and `code`.
base_urlstringFacultatifBase URL override for this run.
job_idstringFacultatifUUID of a saved job to execute. When present, `jobs:execute` is sufficient.

Corps de réponse

ChampType / statutObligatoireDescription
execution_idstringObligatoireUnique execution ID for this test run.
statusstringObligatoireInitial status (typically "pending" or "running").
worker_idstringFacultatifID of the assigned worker, if dispatched immediately.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"test_files":[{"file_name":"checkout.spec.ts","code":"import { test } from "@playwright/test";"}],"base_url":"https://staging.example.com"}' \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/test-runs

Exemple de réponse

{
  "execution_id": "exec-a1b2c3d4",
  "status": "running",
  "worker_id": "worker-1"
}
GET/api/projects/{projectId}/test-runsList test runsJeton utilisateur ou clé API

Returns test runs for the specified project, ordered by most recent first. Job-scoped API keys only receive runs for their bound external job.

Authentification: dual · Scopes: runs:read

# GET /api/projects/{projectId}/test-runs

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireTest run execution ID.
statusstringObligatoireRun status.
job_idstringFacultatifAssociated job UUID, if any.
started_atstringFacultatifISO 8601 start timestamp.
completed_atstringFacultatifISO 8601 completion timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/test-runs

Exemple de réponse

[
  {
    "id": "exec-a1b2c3d4",
    "status": "passed",
    "job_id": "e5f6a7b8-c9d0-1234-efab-345678901234",
    "started_at": "2026-04-04T13:00:00Z",
    "completed_at": "2026-04-04T13:02:15Z"
  }
]
GET/api/projects/{projectId}/statsGet project statsJeton utilisateur ou clé API

Returns exact aggregate execution statistics for the project. Job-scoped API keys receive only their bound external job's execution totals.

Authentification: dual · Scopes: project:read

# GET /api/projects/{projectId}/stats

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
total_runsnumberObligatoireTotal test runs in this project.
pass_ratenumberObligatoirePercentage of passed runs (0-100).
passednumberObligatoirePassed executions.
failednumberObligatoireFailed executions.
errorsnumberObligatoireErrored executions.
runningnumberObligatoirePending or running executions.
avg_duration_msnumberObligatoireAverage duration across executions that reported one.
last_run_atstring | nullObligatoireMost recent execution creation time.
job_countnumberObligatoireSaved jobs in the project for unscoped callers.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/stats

Exemple de réponse

{
  "total_runs": 156,
  "passed": 144,
  "failed": 7,
  "errors": 5,
  "running": 0,
  "avg_duration_ms": 2410,
  "last_run_at": "2026-08-19T12:00:00Z",
  "pass_rate": 92.3,
  "job_count": 12
}
GET/api/projects/{projectId}/run-activityGet project run activityJeton utilisateur ou clé API

Returns exact daily outcome buckets for the requested 1-30 day window. Dates use the requested IANA time zone, and job-scoped API keys receive only their bound external job's executions.

Authentification: dual · Scopes: runs:read

# GET /api/projects/{projectId}/run-activity

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Paramètres de requête

ChampType / statutObligatoireDescription
daysintegerFacultatifNumber of daily buckets to return, from 1 through 30. (Par défaut: 7)
timezonestringFacultatifIANA time zone used to determine each execution's calendar date. (Par défaut: UTC)

Corps de réponse

ChampType / statutObligatoireDescription
[].datestringObligatoireCalendar date in YYYY-MM-DD format.
[].passednumberObligatoireExecutions that passed on this date.
[].unsuccessfulnumberObligatoireExecutions that failed or errored on this date.
[].activenumberObligatoireExecutions that are pending or running on this date.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  "http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/run-activity?days=7&timezone=America%2FToronto"

Exemple de réponse

[
  {
    "date": "2026-08-18",
    "passed": 18,
    "unsuccessful": 2,
    "active": 0
  },
  {
    "date": "2026-08-19",
    "passed": 11,
    "unsuccessful": 1,
    "active": 2
  }
]
GET/api/projects/{projectId}/dashboard-runsGet project dashboard run summariesJeton utilisateur ou clé API

Returns the latest 60 lightweight run summaries and the latest execution for each saved job without transferring execution results or runtime variables.

Authentification: dual · Scopes: runs:read

# GET /api/projects/{projectId}/dashboard-runs

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
recent_runsRunSummary[]ObligatoireAt most 60 runs ordered newest first.
latest_job_runsRunSummary[]ObligatoireLatest execution for each saved job that has run.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/dashboard-runs

Exemple de réponse

{
  "recent_runs": [
    {
      "id": "exec-a1b2c3d4",
      "job_id": "e5f6a7b8-c9d0-1234-efab-345678901234",
      "status": "passed",
      "duration_ms": 2410,
      "created_at": "2026-08-19T12:00:00Z"
    }
  ],
  "latest_job_runs": [
    {
      "id": "exec-a1b2c3d4",
      "job_id": "e5f6a7b8-c9d0-1234-efab-345678901234",
      "status": "passed",
      "duration_ms": 2410,
      "created_at": "2026-08-19T12:00:00Z"
    }
  ]
}
GET/api/test-runs/{executionId}Get test run detailsJeton utilisateur ou clé API

Returns detailed information about a specific test run, including its current status and timing.

Authentification: dual · Scopes: runs:read

# GET /api/test-runs/{executionId}

Paramètres de chemin

ChampType / statutObligatoireDescription
executionIdstringObligatoireExecution ID of the test run.

Corps de réponse

ChampType / statutObligatoireDescription
[]TestExecution[]ObligatoireArray containing the matching execution record.
[].idstringObligatoireTest run execution ID.
[].statusstringObligatoireCurrent run status.
[].project_idstringObligatoireUUID of the parent project.
[].progressProgressSnapshot | nullObligatoireLatest canonical progress snapshot, or null when no progress was reported.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/test-runs/exec-a1b2c3d4

Exemple de réponse

[
  {
    "id": "exec-a1b2c3d4",
    "status": "passed",
    "project_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "worker_id": "worker-1",
    "started_at": "2026-04-04T13:00:00Z",
    "finished_at": "2026-04-04T13:02:15Z"
  }
]
GET/api/test-runs/{executionId}/logsGet test run logsJeton utilisateur ou clé API

Returns the console output and log entries from a test run execution.

Authentification: dual · Scopes: runs:read

# GET /api/test-runs/{executionId}/logs

Paramètres de chemin

ChampType / statutObligatoireDescription
executionIdstringObligatoireExecution ID of the test run.

Paramètres de requête

ChampType / statutObligatoireDescription
limitnumberFacultatifMaximum number of log rows to return. (Par défaut: 50)
offsetnumberFacultatifPagination offset. (Par défaut: 0)

Corps de réponse

ChampType / statutObligatoireDescription
dataLogEntry[]ObligatoireArray of log entries.
totalnumberObligatoireTotal number of log rows for the execution.
data[].timestampstringObligatoireISO 8601 timestamp of the log entry.
data[].levelstringObligatoireLog level: "info", "warn", "error", "debug".
data[].messagestringObligatoireLog message content.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/test-runs/exec-a1b2c3d4/logs

Exemple de réponse

{
  "data": [
    {
      "timestamp": "2026-04-04T13:00:01Z",
      "level": "info",
      "message": "Running test: login.spec.ts"
    },
    {
      "timestamp": "2026-04-04T13:02:15Z",
      "level": "info",
      "message": "All tests passed."
    }
  ],
  "total": 2,
  "limit": 50,
  "offset": 0
}
GET/api/test-runs/{executionId}/stepsGet test run stepsJeton utilisateur ou clé API

Returns the individual test steps and their results from a test run execution.

Authentification: dual · Scopes: runs:read

# GET /api/test-runs/{executionId}/steps

Paramètres de chemin

ChampType / statutObligatoireDescription
executionIdstringObligatoireExecution ID of the test run.

Paramètres de requête

ChampType / statutObligatoireDescription
limitnumberFacultatifMaximum number of step rows to return. (Par défaut: 50)
offsetnumberFacultatifPagination offset. (Par défaut: 0)

Corps de réponse

ChampType / statutObligatoireDescription
dataTestStep[]ObligatoireArray of test steps.
totalnumberObligatoireTotal number of stored step rows for the execution.
data[].eventstringObligatoireStep event name such as test:start, step:start, or step:end.
data[].titlestringFacultatifDisplay title for the step event.
data[].duration_msnumberFacultatifStep duration in milliseconds.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/test-runs/exec-a1b2c3d4/steps

Exemple de réponse

{
  "data": [
    {
      "event": "step:start",
      "title": "navigate to /login",
      "status": "running",
      "duration_ms": 320
    },
    {
      "event": "step:end",
      "title": "fill #email",
      "status": "passed",
      "duration_ms": 45
    }
  ],
  "total": 2,
  "limit": 50,
  "offset": 0
}
POST/api/test-runs/{executionId}/cancelCancel test runJeton utilisateur ou clé API

Marks a running or pending test run as cancelled and broadcasts the updated status to connected clients.

Authentification: dual · Scopes: runs:finish

# POST /api/test-runs/{executionId}/cancel

Paramètres de chemin

ChampType / statutObligatoireDescription
executionIdstringObligatoireExecution ID of the test run to cancel.

Corps de réponse

ChampType / statutObligatoireDescription
execution_idstringObligatoireExecution ID of the cancelled run.
statusstringObligatoireUpdated status ("error").
messagestringObligatoireHuman-readable cancellation message.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/test-runs/exec-a1b2c3d4/cancel

Exemple de réponse

{
  "execution_id": "exec-a1b2c3d4",
  "status": "error",
  "message": "Run cancelled"
}

External Jobs

Create job-scoped automation entry points, inspect external-job health, and run retention cleanup.

GET/api/projects/{projectId}/external-jobsList external jobsJeton utilisateur ou clé API

Returns external jobs for a project. Job-scoped API keys only receive their bound job.

Authentification: dual · Scopes: external_jobs:read

# GET /api/projects/{projectId}/external-jobs

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireProject UUID.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireExternal job UUID.
namestringObligatoireJob display name.
slugstringObligatoireProject-unique slug.
retention_policyobjectObligatoireCurrent retention policy.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/external-jobs

Exemple de réponse

[
  {
    "id": "job-001",
    "name": "Morning billing sync",
    "slug": "morning-billing-sync"
  }
]
POST/api/projects/{projectId}/external-jobsCreate external jobJeton utilisateur ou clé API

Creates a new external job. JWT callers receive the initial plaintext API key once; API-key-authenticated callers receive `api_key: null`.

Authentification: dual · Scopes: external_jobs:write

# POST /api/projects/{projectId}/external-jobs

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireProject UUID.

Corps de requête

ChampType / statutObligatoireDescription
namestringObligatoireJob display name.
descriptionstringFacultatifOptional description.
default_servicestringFacultatifDefault service for future runs.
default_environmentstringFacultatifDefault environment for future runs.

Corps de réponse

ChampType / statutObligatoireDescription
jobobjectObligatoireCreated external job.
api_keyobject | nullObligatoireInitial API key metadata, or `null` for API-key-authenticated callers.
api_key.keystringFacultatifPlaintext key shown only once for JWT callers.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN"   -H "Content-Type: application/json"   -d '{"name":"Morning billing sync"}'   http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/external-jobs

Exemple de réponse

{
  "job": {
    "id": "job-001",
    "name": "Morning billing sync"
  },
  "api_key": {
    "key": "bo_live_abc123"
  }
}
GET/api/external-jobs/{externalJobId}Get external jobJeton utilisateur ou clé API

Returns the full configuration for one external job.

Authentification: dual · Scopes: external_jobs:read

# GET /api/external-jobs/{externalJobId}

Paramètres de chemin

ChampType / statutObligatoireDescription
externalJobIdstringObligatoireExternal job UUID.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireExternal job UUID.
project_idstringObligatoireOwning project UUID.
retention_policyobjectObligatoireRetention policy.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/external-jobs/job-001

Exemple de réponse

[
  {
    "id": "job-001",
    "project_id": "proj-001"
  }
]
PUT/api/external-jobs/{externalJobId}Update external jobJeton utilisateur ou clé API

Updates retention and default metadata for an external job.

Authentification: dual · Scopes: external_jobs:write

# PUT /api/external-jobs/{externalJobId}

Paramètres de chemin

ChampType / statutObligatoireDescription
externalJobIdstringObligatoireExternal job UUID.

Corps de requête

ChampType / statutObligatoireDescription
retention_policyobjectFacultatifUpdated retention policy.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireUpdated job UUID.

Types de contenu: application/json → application/json

Exemple cURL

curl -X PUT -H "Authorization: Bearer YOUR_JWT_TOKEN"   -H "Content-Type: application/json"   -d '{"retention_policy":{"events_days":7,"metrics_days":30,"attachments_days":7,"keep_run_summary_forever":true}}'   http://localhost:8080/api/external-jobs/job-001

Exemple de réponse

[
  {
    "id": "job-001"
  }
]
GET/api/external-jobs/{externalJobId}/statsGet external job statsJeton utilisateur ou clé API

Returns summary metrics such as total runs, pass rate, and average duration.

Authentification: dual · Scopes: external_jobs:read

# GET /api/external-jobs/{externalJobId}/stats

Paramètres de chemin

ChampType / statutObligatoireDescription
externalJobIdstringObligatoireExternal job UUID.

Corps de réponse

ChampType / statutObligatoireDescription
total_runsnumberObligatoireTotal runs for this job.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/external-jobs/job-001/stats

Exemple de réponse

{
  "total_runs": 12,
  "pass_rate": 91.7,
  "avg_duration_ms": 18420
}
GET/api/external-jobs/{externalJobId}/metricsList external job metricsJeton utilisateur ou clé API

Returns metric points for one external job with optional name and time filters.

Authentification: dual · Scopes: external_jobs:read

# GET /api/external-jobs/{externalJobId}/metrics

Paramètres de chemin

ChampType / statutObligatoireDescription
externalJobIdstringObligatoireExternal job UUID.

Paramètres de requête

ChampType / statutObligatoireDescription
namestringFacultatifMetric name to filter by.
fromstringFacultatifInclusive ISO 8601 lower bound for event_at.
tostringFacultatifInclusive ISO 8601 upper bound for event_at.

Corps de réponse

ChampType / statutObligatoireDescription
namestringObligatoireMetric name.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   "http://localhost:8080/api/external-jobs/job-001/metrics?name=invoices.processed"

Exemple de réponse

[
  {
    "name": "invoices.processed",
    "value": 124
  }
]
GET/api/external-jobs/{externalJobId}/runsList external job runsJeton utilisateur ou clé API

Returns paginated runs for one external job.

Authentification: dual · Scopes: external_jobs:read

# GET /api/external-jobs/{externalJobId}/runs

Paramètres de chemin

ChampType / statutObligatoireDescription
externalJobIdstringObligatoireExternal job UUID.

Paramètres de requête

ChampType / statutObligatoireDescription
limitnumberFacultatifMaximum number of runs to return. (Par défaut: 100)
offsetnumberFacultatifPagination offset. (Par défaut: 0)

Corps de réponse

ChampType / statutObligatoireDescription
dataRun[]ObligatoirePaginated run data.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   "http://localhost:8080/api/external-jobs/job-001/runs?limit=5&offset=0"

Exemple de réponse

{
  "data": [
    {
      "id": "run-001",
      "display_name": "Morning billing sync"
    }
  ],
  "total": 1,
  "limit": 5,
  "offset": 0
}
GET/api/external-jobs/{externalJobId}/cleanup-statusGet cleanup statusJeton utilisateur ou clé API

Returns the most recent retention cleanup run for an external job.

Authentification: dual · Scopes: external_jobs:read

# GET /api/external-jobs/{externalJobId}/cleanup-status

Paramètres de chemin

ChampType / statutObligatoireDescription
externalJobIdstringObligatoireExternal job UUID.

Corps de réponse

ChampType / statutObligatoireDescription
cleanupobjectFacultatifLatest cleanup record, if any.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/external-jobs/job-001/cleanup-status

Exemple de réponse

{
  "cleanup": {
    "status": "completed",
    "deleted_logs": 120
  }
}
POST/api/external-jobs/{externalJobId}/cleanupRun retention cleanupJeton utilisateur ou clé API

Triggers retention cleanup for one external job immediately.

Authentification: dual · Scopes: external_jobs:write

# POST /api/external-jobs/{externalJobId}/cleanup

Paramètres de chemin

ChampType / statutObligatoireDescription
externalJobIdstringObligatoireExternal job UUID.

Corps de réponse

ChampType / statutObligatoireDescription
cleanup.statusstringObligatoireCleanup result status.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/external-jobs/job-001/cleanup

Exemple de réponse

{
  "cleanup": {
    "status": "completed",
    "deleted_storage_objects": 1
  }
}

External Ingest

Use a scoped external job key to start runs, stream telemetry, upload attachments, and finish runs from any system.

POST/api/ingest/runsStart external runJeton utilisateur ou clé API

Creates a new external run or returns the existing run when the same external_run_id is retried.

Authentification: dual · Scopes: runs:write

# POST /api/ingest/runs

Corps de requête

ChampType / statutObligatoireDescription
external_job_idstringFacultatifExternal job UUID. Optional when the API key is already job-scoped.
external_run_idstringFacultatifCaller-defined idempotency key for the run.
display_namestringFacultatifHuman-readable run title.

Corps de réponse

ChampType / statutObligatoireDescription
execution_idstringObligatoireCreated or reused execution ID.
duplicatebooleanObligatoireWhether this call reused an existing run.
progress_sequencenumberObligatoireLatest accepted producer sequence, or zero for a new run.
progress_revisionnumberObligatoireLatest persisted server revision, or zero for a new run.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -d '{"external_job_id":"job-001","external_run_id":"cron-2026-04-08T09:00:00Z","display_name":"Morning billing sync"}'   http://localhost:8080/api/ingest/runs

Exemple de réponse

{
  "execution_id": "run-001",
  "status": "running",
  "duplicate": false,
  "progress_sequence": 0,
  "progress_revision": 0
}
POST/api/ingest/runs/{runId}/logsAppend log eventJeton utilisateur ou clé API

Stores one log event for a running external execution.

Authentification: dual · Scopes: logs:write

# POST /api/ingest/runs/{runId}/logs

Paramètres de chemin

ChampType / statutObligatoireDescription
runIdstringObligatoireExecution UUID returned by start run.

Corps de requête

ChampType / statutObligatoireDescription
event_idstringFacultatifIdempotency key for this log.
messagestringObligatoireLog message.

Corps de réponse

ChampType / statutObligatoireDescription
acceptedbooleanObligatoireWhether the event was accepted.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -d '{"event_id":"log-001","message":"Fetched 124 invoices"}'   http://localhost:8080/api/ingest/runs/run-001/logs

Exemple de réponse

{
  "accepted": true,
  "duplicate": false
}
POST/api/ingest/runs/{runId}/stepsAppend step eventJeton utilisateur ou clé API

Stores one step event for the execution timeline.

Authentification: dual · Scopes: steps:write

# POST /api/ingest/runs/{runId}/steps

Paramètres de chemin

ChampType / statutObligatoireDescription
runIdstringObligatoireExecution UUID returned by start run.

Corps de requête

ChampType / statutObligatoireDescription
event_idstringFacultatifIdempotency key for this step event.
eventstringObligatoireEvent name such as step:start or step:end.
titlestringFacultatifDisplay title for the step.

Corps de réponse

ChampType / statutObligatoireDescription
acceptedbooleanObligatoireWhether the event was accepted.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -d '{"event":"step:start","title":"Fetch invoices"}'   http://localhost:8080/api/ingest/runs/run-001/steps

Exemple de réponse

{
  "accepted": true,
  "duplicate": false
}
POST/api/ingest/runs/{runId}/metricsAppend metric pointJeton utilisateur ou clé API

Stores one metric sample for the execution.

Authentification: dual · Scopes: metrics:write

# POST /api/ingest/runs/{runId}/metrics

Paramètres de chemin

ChampType / statutObligatoireDescription
runIdstringObligatoireExecution UUID returned by start run.

Corps de requête

ChampType / statutObligatoireDescription
event_idstringFacultatifIdempotency key for this metric sample.
namestringObligatoireMetric name.
kindstringObligatoiregauge, count, rate, or duration.
valuenumberObligatoireMetric value.

Corps de réponse

ChampType / statutObligatoireDescription
acceptedbooleanObligatoireWhether the metric was accepted.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -d '{"name":"invoices.processed","kind":"count","value":124}'   http://localhost:8080/api/ingest/runs/run-001/metrics

Exemple de réponse

{
  "accepted": true,
  "duplicate": false
}
POST/api/ingest/runs/{runId}/progressReport run progressJeton utilisateur ou clé API

Atomically stores count, percent-only, or indeterminate progress. Exact event retries return the original canonical snapshot.

Authentification: dual · Scopes: progress:write

# POST /api/ingest/runs/{runId}/progress

Paramètres de chemin

ChampType / statutObligatoireDescription
runIdstringObligatoireExecution UUID returned by start run.

Corps de requête

ChampType / statutObligatoireDescription
event_idstringObligatoireStable idempotency key for this progress report.
sequencenumberObligatoirePositive increasing producer sequence.
currentnumberFacultatifCurrent count; provide with total only.
totalnumberFacultatifPositive total count; provide with current only.
percentnumberFacultatifPercent-only progress from 0 through 100.
stagestringFacultatifCurrent stage, up to 128 characters.
messagestringFacultatifProgress message, up to 1024 characters.

Corps de réponse

ChampType / statutObligatoireDescription
acceptedbooleanObligatoireWhether the report was accepted.
duplicatebooleanObligatoireWhether this was an exact retry.
progressProgressSnapshotObligatoireCanonical persisted snapshot with server revision.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -d '{"event_id":"progress-001","sequence":1,"current":62,"total":100,"stage":"processing"}'   http://localhost:8080/api/ingest/runs/run-001/progress

Exemple de réponse

{
  "accepted": true,
  "duplicate": false,
  "progress": {
    "execution_id": "run-001",
    "event_id": "progress-001",
    "sequence": 1,
    "revision": 1,
    "mode": "count",
    "current": 62,
    "total": 100,
    "percent": 62,
    "stage": "processing",
    "message": "Processed 62 invoices",
    "reported_at": "2026-04-08T09:00:32Z",
    "updated_at": "2026-04-08T09:00:32.100Z"
  }
}
POST/api/ingest/runs/{runId}/attachmentsUpload attachmentJeton utilisateur ou clé API

Streams one supported attachment into the private execution-attachments bucket and stores metadata on the run.

Authentification: dual · Scopes: attachments:write

# POST /api/ingest/runs/{runId}/attachments

Paramètres de chemin

ChampType / statutObligatoireDescription
runIdstringObligatoireExecution UUID returned by start run.

Corps de requête

ChampType / statutObligatoireDescription
filemultipart fileObligatoireSupported file to upload.
event_idstringFacultatifIdempotency key for this attachment.

Corps de réponse

ChampType / statutObligatoireDescription
attachment_idstringObligatoireCreated attachment UUID.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -F "[email protected];type=application/json"   -F "event_id=att-001"   http://localhost:8080/api/ingest/runs/run-001/attachments

Exemple de réponse

{
  "attachment_id": "att-001",
  "file_name": "report.json"
}
POST/api/ingest/runs/{runId}/heartbeatUpdate heartbeatJeton utilisateur ou clé API

Updates the last heartbeat timestamp for a running external execution.

Authentification: dual · Scopes: runs:write

# POST /api/ingest/runs/{runId}/heartbeat

Paramètres de chemin

ChampType / statutObligatoireDescription
runIdstringObligatoireExecution UUID returned by start run.

Corps de requête

ChampType / statutObligatoireDescription
heartbeat_atstringFacultatifOptional ISO 8601 heartbeat timestamp.

Corps de réponse

ChampType / statutObligatoireDescription
last_heartbeat_atstringObligatoireStored heartbeat timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -d '{"heartbeat_at":"2026-04-08T09:05:00Z"}'   http://localhost:8080/api/ingest/runs/run-001/heartbeat

Exemple de réponse

{
  "execution_id": "run-001",
  "last_heartbeat_at": "2026-04-08T09:05:00Z"
}
POST/api/ingest/runs/{runId}/completeComplete external runJeton utilisateur ou clé API

Marks the external execution as passed and stores a final summary.

Authentification: dual · Scopes: runs:finish

# POST /api/ingest/runs/{runId}/complete

Paramètres de chemin

ChampType / statutObligatoireDescription
runIdstringObligatoireExecution UUID returned by start run.

Corps de requête

ChampType / statutObligatoireDescription
finished_atstringFacultatifISO 8601 finish timestamp.
duration_msnumberFacultatifExecution duration in milliseconds.

Corps de réponse

ChampType / statutObligatoireDescription
statusstringObligatoireFinal execution status.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -d '{"finished_at":"2026-04-08T09:10:00Z","duration_ms":600000}'   http://localhost:8080/api/ingest/runs/run-001/complete

Exemple de réponse

{
  "execution_id": "run-001",
  "status": "passed"
}
POST/api/ingest/runs/{runId}/failFail external runJeton utilisateur ou clé API

Marks the external execution as failed.

Authentification: dual · Scopes: runs:finish

# POST /api/ingest/runs/{runId}/fail

Paramètres de chemin

ChampType / statutObligatoireDescription
runIdstringObligatoireExecution UUID returned by start run.

Corps de requête

ChampType / statutObligatoireDescription
errorstringObligatoireError message describing the failure.

Corps de réponse

ChampType / statutObligatoireDescription
statusstringObligatoireFinal execution status.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -d '{"error":"Unable to process invoices"}'   http://localhost:8080/api/ingest/runs/run-001/fail

Exemple de réponse

{
  "execution_id": "run-001",
  "status": "failed"
}
GET/api/test-runs/{executionId}/metricsGet run metricsJeton utilisateur ou clé API

Returns paginated metric points for one execution.

Authentification: dual · Scopes: runs:read

# GET /api/test-runs/{executionId}/metrics

Paramètres de chemin

ChampType / statutObligatoireDescription
executionIdstringObligatoireExecution UUID.

Paramètres de requête

ChampType / statutObligatoireDescription
limitnumberFacultatifMaximum records to return. (Par défaut: 100)
offsetnumberFacultatifPagination offset. (Par défaut: 0)

Corps de réponse

ChampType / statutObligatoireDescription
dataMetric[]ObligatoirePaginated metric data.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   "http://localhost:8080/api/test-runs/run-001/metrics?limit=100&offset=0"

Exemple de réponse

{
  "data": [
    {
      "name": "invoices.processed",
      "value": 124,
      "unit": "items"
    }
  ],
  "total": 1,
  "limit": 100,
  "offset": 0
}
GET/api/test-runs/{executionId}/progressGet run progress historyJeton utilisateur ou clé API

Returns paginated canonical progress snapshots ordered by server revision.

Authentification: dual · Scopes: runs:read

# GET /api/test-runs/{executionId}/progress

Paramètres de chemin

ChampType / statutObligatoireDescription
executionIdstringObligatoireExecution UUID.

Paramètres de requête

ChampType / statutObligatoireDescription
limitnumberFacultatifMaximum records to return. (Par défaut: 50)
offsetnumberFacultatifPagination offset. (Par défaut: 0)

Corps de réponse

ChampType / statutObligatoireDescription
dataProgressSnapshot[]ObligatoireCanonical progress history.
totalnumberObligatoireTotal retained progress events.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   "http://localhost:8080/api/test-runs/run-001/progress?limit=50&offset=0"

Exemple de réponse

{
  "data": [
    {
      "execution_id": "run-001",
      "event_id": "progress-001",
      "sequence": 1,
      "revision": 1,
      "mode": "percent",
      "current": null,
      "total": null,
      "percent": 72.5,
      "stage": "uploading",
      "message": null,
      "reported_at": "2026-04-08T09:05:32Z",
      "updated_at": "2026-04-08T09:05:32.100Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}
GET/api/test-runs/{executionId}/attachmentsGet run attachmentsJeton utilisateur ou clé API

Returns paginated attachment metadata for one execution.

Authentification: dual · Scopes: runs:read

# GET /api/test-runs/{executionId}/attachments

Paramètres de chemin

ChampType / statutObligatoireDescription
executionIdstringObligatoireExecution UUID.

Paramètres de requête

ChampType / statutObligatoireDescription
limitnumberFacultatifMaximum records to return. (Par défaut: 50)
offsetnumberFacultatifPagination offset. (Par défaut: 0)

Corps de réponse

ChampType / statutObligatoireDescription
dataAttachment[]ObligatoirePaginated attachment data.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   "http://localhost:8080/api/test-runs/run-001/attachments?limit=50&offset=0"

Exemple de réponse

{
  "data": [
    {
      "file_name": "report.json",
      "content_type": "application/json",
      "size_bytes": 17
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}
GET/api/test-runs/{executionId}/attachments/{attachmentId}/downloadGet attachment download URLJeton utilisateur ou clé API

Returns a short-lived signed URL for downloading a private run attachment.

Authentification: dual · Scopes: runs:read

# GET /api/test-runs/{executionId}/attachments/{attachmentId}/download

Paramètres de chemin

ChampType / statutObligatoireDescription
executionIdstringObligatoireExecution UUID.
attachmentIdstringObligatoireAttachment UUID.

Corps de réponse

ChampType / statutObligatoireDescription
attachment_idstringObligatoireAttachment UUID.
file_namestringObligatoireAttachment file name.
content_typestringObligatoireAttachment content type.
download_urlstringObligatoireShort-lived signed download URL.
expires_atstringObligatoireISO 8601 expiration timestamp for the signed URL.
expires_in_secondsnumberObligatoireSigned URL lifetime in seconds.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/test-runs/run-001/attachments/att-001/download

Exemple de réponse

{
  "attachment_id": "att-001",
  "file_name": "report.json",
  "content_type": "application/json",
  "download_url": "http://127.0.0.1:54321/storage/v1/object/sign/execution-attachments/project/...",
  "expires_at": "2026-04-08T09:06:00Z",
  "expires_in_seconds": 300
}

Wiki

Manage the independent project wiki. Dual-auth routes accept a project member JWT or a project-bound API key with all documented wiki scopes. API keys never gain archive, unarchive, attachment-delete, or archive-import administration rights. Authentication middleware may return plain-text 401/403 errors before a coded wiki response.

GET/api/projects/{projectId}/wiki/pagesList or search wiki pagesJeton utilisateur ou clé API

Returns bounded page summaries without Markdown bodies, plus the normalized search options and caller capabilities. Results come from the project-scoped full-text search and can include active, archived, or all pages.

Authentification: dual · Scopes: wiki:read

# GET /api/projects/{projectId}/wiki/pages

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.

Paramètres de requête

ChampType / statutObligatoireDescription
qstringFacultatifTrimmed full-text query, at most 500 Unicode characters.
archiveactive | archived | allFacultatifArchive-state filter. (Par défaut: active)
limitintegerFacultatifMaximum page summaries, from 1 through 100. (Par défaut: 50)
offsetintegerFacultatifZero-based result offset, from 0 through 10000. (Par défaut: 0)

Corps de réponse

ChampType / statutObligatoireDescription
pagesWikiPageSummary[]ObligatoireSummaries with id, project_id, title, slug, filename, revision, archived_at, updated_at, and numeric rank; body_markdown is intentionally omitted.
qstringObligatoireNormalized query.
archiveactive | archived | allObligatoireApplied archive filter.
limitintegerObligatoireApplied limit.
offsetintegerObligatoireApplied offset.
capabilities.can_createbooleanObligatoireWhether this principal can create pages.
capabilities.can_exportbooleanObligatoireAlways true after project read authorization.
capabilities.can_importbooleanObligatoireTrue only for an authorized JWT project administrator.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
invalid_wiki_search400Facultatifq, archive, limit, or offset is outside the accepted contract.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   "http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages?q=incident&archive=active&limit=50&offset=0"

Exemple de réponse

{
  "pages": [
    {
      "id": "d2600000-0000-0000-0000-000000000201",
      "project_id": "b0000000-0000-0000-0000-000000000001",
      "title": "Incident response",
      "slug": "incident-response",
      "filename": "runbooks/incident-response.md",
      "revision": 3,
      "archived_at": null,
      "updated_at": "2026-08-16T10:30:00Z",
      "rank": 0.42
    }
  ],
  "q": "incident",
  "archive": "active",
  "limit": 50,
  "offset": 0,
  "capabilities": {
    "can_create": true,
    "can_export": true,
    "can_import": false
  }
}
POST/api/projects/{projectId}/wiki/pagesCreate a wiki pageJeton utilisateur ou clé API

Creates revision 1 transactionally. JWT users need project mutation access; API keys need wiki:write and Idempotency-Key. Slug defaults from title, filename defaults from slug, and Markdown defaults to empty. JSON is capped at 8 MiB and unknown fields are rejected.

Authentification: dual · Scopes: wiki:write

# POST /api/projects/{projectId}/wiki/pages

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.

En-têtes de requête

ChampType / statutObligatoireDescription
Idempotency-KeystringFacultatifRequired for API-key commands and optional for JWT commands. After trimming, must be 1-255 Unicode characters. An exact retry by the same actor replays the saved result; reuse for different input returns idempotency_mismatch.

Corps de requête

ChampType / statutObligatoireDescription
titlestringObligatoireTitle normalized by trimming; final length is 1-300 characters.
slugstringFacultatifSource for a lowercase kebab-case slug, at most 200 characters. Defaults to title.
filenamestringFacultatifSource for a lowercase relative .md path, 3-512 characters. Defaults to {slug}.md.
body_markdownstringFacultatifUTF-8 Markdown; canonical result is at most 1 MiB.

En-têtes de réponse

ChampType / statutObligatoireDescription
ETagstrong ETagObligatoireCurrent page version in the form "wiki-page:{pageId}:rev:{revision}". A revision_conflict response also returns the current value.

Corps de réponse

ChampType / statutObligatoireDescription
outcomeapplied | noopObligatoireWhether this command changed the page.
codestringObligatoireStable success/no-op code for this command.
page.idUUIDObligatoirePage UUID.
page.project_idUUIDObligatoireOwning project UUID.
page.titlestringObligatoireTrimmed title, 1-300 characters.
page.slugstringObligatoireLowercase kebab-case slug, at most 200 characters.
page.normalized_slugstringObligatoireStored normalized slug used for project uniqueness.
page.filenamestringObligatoireLowercase project-relative .md filename, 3-512 characters.
page.normalized_filenamestringObligatoireStored normalized filename used for project uniqueness.
page.body_markdownstringObligatoireCanonical Markdown head, at most 1 MiB; CRLF/CR is normalized to LF and non-empty content ends with LF.
page.revisionintegerObligatoireCurrent positive revision, up to 9007199254740991.
page.archived_atISO 8601 string | nullObligatoireArchive timestamp, or null while active.
page.created_actor_kinduser | api_key | systemObligatoirePrincipal kind that created the page.
page.created_actor_user_idUUIDFacultatifCreating user ID when actor_kind is user.
page.created_actor_api_key_idUUIDFacultatifCreating API key ID when actor_kind is api_key.
page.created_actor_displaystring | nullObligatoireStored display identity for the creating actor.
page.updated_actor_kinduser | api_key | systemObligatoirePrincipal kind that last changed the page.
page.updated_actor_user_idUUIDFacultatifLast updating user ID when actor_kind is user.
page.updated_actor_api_key_idUUIDFacultatifLast updating API key ID when actor_kind is api_key.
page.updated_actor_displaystring | nullObligatoireStored display identity for the last updating actor.
page.created_atISO 8601 stringObligatoireCreation timestamp.
page.updated_atISO 8601 stringObligatoireLast update timestamp.
audit_event_idUUID | nullObligatoireAppend-only audit event ID, or null for a no-op.
source_revisionintegerFacultatifSource revision on a restore result.
replayedbooleanObligatoireTrue when an exact Idempotency-Key retry replayed this result.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
invalid_json_body400FacultatifThe body is not one JSON value, contains unknown fields, or has invalid field types.
request_body_too_large413FacultatifThe JSON request exceeds the route's byte limit.
invalid_idempotency_key400FacultatifAn API-key command omitted Idempotency-Key or the trimmed value exceeds 255 characters.
idempotency_mismatch409FacultatifThe same actor already used this Idempotency-Key for different canonical command input.
invalid_title400FacultatifThe normalized title is empty or longer than 300 characters.
invalid_slug400FacultatifThe normalized slug is empty, longer than 200 characters, or cannot match lowercase kebab-case.
invalid_filename400FacultatifThe normalized Markdown filename is invalid, hidden, non-canonical, or longer than 512 characters.
markdown_too_large413FacultatifCanonical UTF-8 Markdown exceeds 1 MiB.
wiki_slug_conflict409FacultatifAnother project wiki page already uses the normalized slug.
wiki_filename_conflict409FacultatifAnother project wiki page already uses the normalized filename.
revision_exhausted409FacultatifThe page reached revision 9007199254740991.
wiki_attachment_reference_not_found409FacultatifMarkdown references an attachment that does not exist on this project page.
invalid_create_input400Facultatiftitle is missing or a request field has an invalid type.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -H "Idempotency-Key: create-incident-response-v1"   -d '{"title":"Incident response","slug":"incident-response","filename":"runbooks/incident-response.md","body_markdown":"# Incident response\n"}'   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages

Exemple de réponse

{
  "outcome": "applied",
  "code": "wiki_page_created",
  "page": {
    "id": "d2600000-0000-0000-0000-000000000201",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "title": "Incident response",
    "slug": "incident-response",
    "normalized_slug": "incident-response",
    "filename": "runbooks/incident-response.md",
    "normalized_filename": "runbooks/incident-response.md",
    "body_markdown": "# Incident response\n",
    "revision": 1,
    "archived_at": null,
    "created_actor_kind": "api_key",
    "created_actor_api_key_id": "d2600000-0000-0000-0000-000000000401",
    "created_actor_display": "d2600000-0000-0000-0000-000000000401",
    "updated_actor_kind": "api_key",
    "updated_actor_api_key_id": "d2600000-0000-0000-0000-000000000401",
    "updated_actor_display": "d2600000-0000-0000-0000-000000000401",
    "created_at": "2026-08-16T10:00:00Z",
    "updated_at": "2026-08-16T10:00:00Z"
  },
  "audit_event_id": "d2600000-0000-0000-0000-000000000501",
  "replayed": false
}
GET/api/projects/{projectId}/wiki/pages/{pageId}Get a wiki pageJeton utilisateur ou clé API

Returns the current page head, including canonical Markdown, actor metadata, archive state, and capabilities calculated for the principal.

Authentification: dual · Scopes: wiki:read

# GET /api/projects/{projectId}/wiki/pages/{pageId}

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.

En-têtes de réponse

ChampType / statutObligatoireDescription
ETagstrong ETagObligatoireCurrent page version in the form "wiki-page:{pageId}:rev:{revision}". A revision_conflict response also returns the current value.

Corps de réponse

ChampType / statutObligatoireDescription
page.idUUIDObligatoirePage UUID.
page.project_idUUIDObligatoireOwning project UUID.
page.titlestringObligatoireTrimmed title, 1-300 characters.
page.slugstringObligatoireLowercase kebab-case slug, at most 200 characters.
page.normalized_slugstringObligatoireStored normalized slug used for project uniqueness.
page.filenamestringObligatoireLowercase project-relative .md filename, 3-512 characters.
page.normalized_filenamestringObligatoireStored normalized filename used for project uniqueness.
page.body_markdownstringObligatoireCanonical Markdown head, at most 1 MiB; CRLF/CR is normalized to LF and non-empty content ends with LF.
page.revisionintegerObligatoireCurrent positive revision, up to 9007199254740991.
page.archived_atISO 8601 string | nullObligatoireArchive timestamp, or null while active.
page.created_actor_kinduser | api_key | systemObligatoirePrincipal kind that created the page.
page.created_actor_user_idUUIDFacultatifCreating user ID when actor_kind is user.
page.created_actor_api_key_idUUIDFacultatifCreating API key ID when actor_kind is api_key.
page.created_actor_displaystring | nullObligatoireStored display identity for the creating actor.
page.updated_actor_kinduser | api_key | systemObligatoirePrincipal kind that last changed the page.
page.updated_actor_user_idUUIDFacultatifLast updating user ID when actor_kind is user.
page.updated_actor_api_key_idUUIDFacultatifLast updating API key ID when actor_kind is api_key.
page.updated_actor_displaystring | nullObligatoireStored display identity for the last updating actor.
page.created_atISO 8601 stringObligatoireCreation timestamp.
page.updated_atISO 8601 stringObligatoireLast update timestamp.
capabilities.can_readbooleanObligatoireTrue after read authorization.
capabilities.can_exportbooleanObligatoireTrue after read authorization.
capabilities.can_updatebooleanObligatoireTrue for a mutable active page and a mutation-capable principal.
capabilities.can_restorebooleanObligatoireTrue for a mutation-capable principal, including on archived pages.
capabilities.can_archivebooleanObligatoireTrue only for a JWT administrator and an active page.
capabilities.can_unarchivebooleanObligatoireTrue only for a JWT administrator and an archived page.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.

Types de contenu: application/json → application/json

Exemple cURL

curl -i -H "Authorization: Bearer YOUR_JWT_TOKEN"   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201

Exemple de réponse

{
  "page": {
    "id": "d2600000-0000-0000-0000-000000000201",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "title": "Incident response",
    "slug": "incident-response",
    "normalized_slug": "incident-response",
    "filename": "runbooks/incident-response.md",
    "normalized_filename": "runbooks/incident-response.md",
    "body_markdown": "# Incident response\n",
    "revision": 1,
    "archived_at": null,
    "created_actor_kind": "user",
    "created_actor_user_id": "d2600000-0000-0000-0000-000000000301",
    "created_actor_display": "d2600000-0000-0000-0000-000000000301",
    "updated_actor_kind": "user",
    "updated_actor_user_id": "d2600000-0000-0000-0000-000000000301",
    "updated_actor_display": "d2600000-0000-0000-0000-000000000301",
    "created_at": "2026-08-16T10:00:00Z",
    "updated_at": "2026-08-16T10:00:00Z"
  },
  "capabilities": {
    "can_read": true,
    "can_export": true,
    "can_update": true,
    "can_restore": true,
    "can_archive": true,
    "can_unarchive": false
  }
}
PUT/api/projects/{projectId}/wiki/pages/{pageId}Update a wiki pageJeton utilisateur ou clé API

Applies a partial page-head update under exact ETag concurrency. API keys need both wiki:read and wiki:write because successful and no-op responses include the current page body. Omitted fields are unchanged; an empty or equivalent change is a wiki_page_unchanged no-op. Archived pages cannot be updated. JSON is capped at 8 MiB and unknown fields are rejected.

Authentification: dual · Scopes: wiki:read wiki:write

# PUT /api/projects/{projectId}/wiki/pages/{pageId}

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.

En-têtes de requête

ChampType / statutObligatoireDescription
If-Matchstrong ETagObligatoireExact current page ETag: "wiki-page:{pageId}:rev:{revision}". Weak tags, *, lists, another page ID, and non-canonical revision numbers are rejected.
Idempotency-KeystringFacultatifRequired for API-key commands and optional for JWT commands. After trimming, must be 1-255 Unicode characters. An exact retry by the same actor replays the saved result; reuse for different input returns idempotency_mismatch.

Corps de requête

ChampType / statutObligatoireDescription
titlestringFacultatifTrimmed title, 1-300 characters.
slugstringFacultatifLowercase kebab-case slug, at most 200 characters.
filenamestringFacultatifLowercase project-relative .md filename, 3-512 characters.
body_markdownstringFacultatifCanonical Markdown head, at most 1 MiB; CRLF/CR is normalized to LF and non-empty content ends with LF.

En-têtes de réponse

ChampType / statutObligatoireDescription
ETagstrong ETagObligatoireCurrent page version in the form "wiki-page:{pageId}:rev:{revision}". A revision_conflict response also returns the current value.

Corps de réponse

ChampType / statutObligatoireDescription
outcomeapplied | noopObligatoireWhether this command changed the page.
codestringObligatoireStable success/no-op code for this command.
page.idUUIDObligatoirePage UUID.
page.project_idUUIDObligatoireOwning project UUID.
page.titlestringObligatoireTrimmed title, 1-300 characters.
page.slugstringObligatoireLowercase kebab-case slug, at most 200 characters.
page.normalized_slugstringObligatoireStored normalized slug used for project uniqueness.
page.filenamestringObligatoireLowercase project-relative .md filename, 3-512 characters.
page.normalized_filenamestringObligatoireStored normalized filename used for project uniqueness.
page.body_markdownstringObligatoireCanonical Markdown head, at most 1 MiB; CRLF/CR is normalized to LF and non-empty content ends with LF.
page.revisionintegerObligatoireCurrent positive revision, up to 9007199254740991.
page.archived_atISO 8601 string | nullObligatoireArchive timestamp, or null while active.
page.created_actor_kinduser | api_key | systemObligatoirePrincipal kind that created the page.
page.created_actor_user_idUUIDFacultatifCreating user ID when actor_kind is user.
page.created_actor_api_key_idUUIDFacultatifCreating API key ID when actor_kind is api_key.
page.created_actor_displaystring | nullObligatoireStored display identity for the creating actor.
page.updated_actor_kinduser | api_key | systemObligatoirePrincipal kind that last changed the page.
page.updated_actor_user_idUUIDFacultatifLast updating user ID when actor_kind is user.
page.updated_actor_api_key_idUUIDFacultatifLast updating API key ID when actor_kind is api_key.
page.updated_actor_displaystring | nullObligatoireStored display identity for the last updating actor.
page.created_atISO 8601 stringObligatoireCreation timestamp.
page.updated_atISO 8601 stringObligatoireLast update timestamp.
audit_event_idUUID | nullObligatoireAppend-only audit event ID, or null for a no-op.
source_revisionintegerFacultatifSource revision on a restore result.
replayedbooleanObligatoireTrue when an exact Idempotency-Key retry replayed this result.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.
invalid_json_body400FacultatifThe body is not one JSON value, contains unknown fields, or has invalid field types.
request_body_too_large413FacultatifThe JSON request exceeds the route's byte limit.
invalid_idempotency_key400FacultatifAn API-key command omitted Idempotency-Key or the trimmed value exceeds 255 characters.
idempotency_mismatch409FacultatifThe same actor already used this Idempotency-Key for different canonical command input.
invalid_title400FacultatifThe normalized title is empty or longer than 300 characters.
invalid_slug400FacultatifThe normalized slug is empty, longer than 200 characters, or cannot match lowercase kebab-case.
invalid_filename400FacultatifThe normalized Markdown filename is invalid, hidden, non-canonical, or longer than 512 characters.
markdown_too_large413FacultatifCanonical UTF-8 Markdown exceeds 1 MiB.
wiki_slug_conflict409FacultatifAnother project wiki page already uses the normalized slug.
wiki_filename_conflict409FacultatifAnother project wiki page already uses the normalized filename.
revision_exhausted409FacultatifThe page reached revision 9007199254740991.
wiki_attachment_reference_not_found409FacultatifMarkdown references an attachment that does not exist on this project page.
if_match_required428FacultatifIf-Match is required for this page command.
invalid_if_match400FacultatifIf-Match is not the exact strong ETag for this page.
revision_conflict412FacultatifThe page has changed. The error details include expected_revision, current_revision, and current_etag; the response ETag is current.
invalid_update_changes400FacultatifA change is unknown, null, or not a string.
wiki_page_archived409FacultatifArchived pages cannot be updated.

Types de contenu: application/json → application/json

Exemple cURL

curl -X PUT -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -H 'If-Match: "wiki-page:d2600000-0000-0000-0000-000000000201:rev:1"'   -H "Idempotency-Key: update-incident-response-v2"   -d '{"title":"Incident response plan"}'   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201

Exemple de réponse

{
  "outcome": "applied",
  "code": "wiki_page_updated",
  "page": {
    "id": "d2600000-0000-0000-0000-000000000201",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "revision": 2,
    "title": "Incident response plan"
  },
  "audit_event_id": "d2600000-0000-0000-0000-000000000502",
  "replayed": false
}
POST/api/projects/{projectId}/wiki/pages/{pageId}/archiveArchive a wiki pageJeton utilisateur

JWT-admin-only soft archive under exact ETag concurrency. API keys are rejected regardless of scope. An already archived page returns a wiki_page_already_archived no-op. The body may be omitted or be exactly {}; non-empty JSON is rejected and the body limit is 1 KiB.

Authentification: jwt_only · Scopes: —

# POST /api/projects/{projectId}/wiki/pages/{pageId}/archive

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.

En-têtes de requête

ChampType / statutObligatoireDescription
If-Matchstrong ETagObligatoireExact current page ETag: "wiki-page:{pageId}:rev:{revision}". Weak tags, *, lists, another page ID, and non-canonical revision numbers are rejected.
Idempotency-KeystringFacultatifRequired for API-key commands and optional for JWT commands. After trimming, must be 1-255 Unicode characters. An exact retry by the same actor replays the saved result; reuse for different input returns idempotency_mismatch.

En-têtes de réponse

ChampType / statutObligatoireDescription
ETagstrong ETagObligatoireCurrent page version in the form "wiki-page:{pageId}:rev:{revision}". A revision_conflict response also returns the current value.

Corps de réponse

ChampType / statutObligatoireDescription
outcomeapplied | noopObligatoireWhether this command changed the page.
codestringObligatoireStable success/no-op code for this command.
page.idUUIDObligatoirePage UUID.
page.project_idUUIDObligatoireOwning project UUID.
page.titlestringObligatoireTrimmed title, 1-300 characters.
page.slugstringObligatoireLowercase kebab-case slug, at most 200 characters.
page.normalized_slugstringObligatoireStored normalized slug used for project uniqueness.
page.filenamestringObligatoireLowercase project-relative .md filename, 3-512 characters.
page.normalized_filenamestringObligatoireStored normalized filename used for project uniqueness.
page.body_markdownstringObligatoireCanonical Markdown head, at most 1 MiB; CRLF/CR is normalized to LF and non-empty content ends with LF.
page.revisionintegerObligatoireCurrent positive revision, up to 9007199254740991.
page.archived_atISO 8601 string | nullObligatoireArchive timestamp, or null while active.
page.created_actor_kinduser | api_key | systemObligatoirePrincipal kind that created the page.
page.created_actor_user_idUUIDFacultatifCreating user ID when actor_kind is user.
page.created_actor_api_key_idUUIDFacultatifCreating API key ID when actor_kind is api_key.
page.created_actor_displaystring | nullObligatoireStored display identity for the creating actor.
page.updated_actor_kinduser | api_key | systemObligatoirePrincipal kind that last changed the page.
page.updated_actor_user_idUUIDFacultatifLast updating user ID when actor_kind is user.
page.updated_actor_api_key_idUUIDFacultatifLast updating API key ID when actor_kind is api_key.
page.updated_actor_displaystring | nullObligatoireStored display identity for the last updating actor.
page.created_atISO 8601 stringObligatoireCreation timestamp.
page.updated_atISO 8601 stringObligatoireLast update timestamp.
audit_event_idUUID | nullObligatoireAppend-only audit event ID, or null for a no-op.
source_revisionintegerFacultatifSource revision on a restore result.
replayedbooleanObligatoireTrue when an exact Idempotency-Key retry replayed this result.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_admin_required403FacultatifThe operation requires a JWT user who is a workspace owner/admin or explicit project admin. API keys cannot perform it.
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.
invalid_json_body400FacultatifThe body is not one JSON value, contains unknown fields, or has invalid field types.
request_body_too_large413FacultatifThe JSON request exceeds the route's byte limit.
invalid_idempotency_key400FacultatifAn API-key command omitted Idempotency-Key or the trimmed value exceeds 255 characters.
idempotency_mismatch409FacultatifThe same actor already used this Idempotency-Key for different canonical command input.
if_match_required428FacultatifIf-Match is required for this page command.
invalid_if_match400FacultatifIf-Match is not the exact strong ETag for this page.
revision_conflict412FacultatifThe page has changed. The error details include expected_revision, current_revision, and current_etag; the response ETag is current.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN"   -H "Content-Type: application/json"   -H 'If-Match: "wiki-page:d2600000-0000-0000-0000-000000000201:rev:1"'   -H "Idempotency-Key: archive-incident-response-v1"   -d '{}'   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/archive

Exemple de réponse

{
  "outcome": "applied",
  "code": "wiki_page_archived",
  "page": {
    "id": "d2600000-0000-0000-0000-000000000201",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "revision": 2,
    "archived_at": "2026-08-16T11:00:00Z"
  },
  "audit_event_id": "d2600000-0000-0000-0000-000000000503",
  "replayed": false
}
POST/api/projects/{projectId}/wiki/pages/{pageId}/unarchiveUnarchive a wiki pageJeton utilisateur

JWT-admin-only reactivation under exact ETag concurrency. API keys are rejected regardless of scope. An already active page returns a wiki_page_already_active no-op. The body may be omitted or be exactly {}; non-empty JSON is rejected and the body limit is 1 KiB.

Authentification: jwt_only · Scopes: —

# POST /api/projects/{projectId}/wiki/pages/{pageId}/unarchive

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.

En-têtes de requête

ChampType / statutObligatoireDescription
If-Matchstrong ETagObligatoireExact current page ETag: "wiki-page:{pageId}:rev:{revision}". Weak tags, *, lists, another page ID, and non-canonical revision numbers are rejected.
Idempotency-KeystringFacultatifRequired for API-key commands and optional for JWT commands. After trimming, must be 1-255 Unicode characters. An exact retry by the same actor replays the saved result; reuse for different input returns idempotency_mismatch.

En-têtes de réponse

ChampType / statutObligatoireDescription
ETagstrong ETagObligatoireCurrent page version in the form "wiki-page:{pageId}:rev:{revision}". A revision_conflict response also returns the current value.

Corps de réponse

ChampType / statutObligatoireDescription
outcomeapplied | noopObligatoireWhether this command changed the page.
codestringObligatoireStable success/no-op code for this command.
page.idUUIDObligatoirePage UUID.
page.project_idUUIDObligatoireOwning project UUID.
page.titlestringObligatoireTrimmed title, 1-300 characters.
page.slugstringObligatoireLowercase kebab-case slug, at most 200 characters.
page.normalized_slugstringObligatoireStored normalized slug used for project uniqueness.
page.filenamestringObligatoireLowercase project-relative .md filename, 3-512 characters.
page.normalized_filenamestringObligatoireStored normalized filename used for project uniqueness.
page.body_markdownstringObligatoireCanonical Markdown head, at most 1 MiB; CRLF/CR is normalized to LF and non-empty content ends with LF.
page.revisionintegerObligatoireCurrent positive revision, up to 9007199254740991.
page.archived_atISO 8601 string | nullObligatoireArchive timestamp, or null while active.
page.created_actor_kinduser | api_key | systemObligatoirePrincipal kind that created the page.
page.created_actor_user_idUUIDFacultatifCreating user ID when actor_kind is user.
page.created_actor_api_key_idUUIDFacultatifCreating API key ID when actor_kind is api_key.
page.created_actor_displaystring | nullObligatoireStored display identity for the creating actor.
page.updated_actor_kinduser | api_key | systemObligatoirePrincipal kind that last changed the page.
page.updated_actor_user_idUUIDFacultatifLast updating user ID when actor_kind is user.
page.updated_actor_api_key_idUUIDFacultatifLast updating API key ID when actor_kind is api_key.
page.updated_actor_displaystring | nullObligatoireStored display identity for the last updating actor.
page.created_atISO 8601 stringObligatoireCreation timestamp.
page.updated_atISO 8601 stringObligatoireLast update timestamp.
audit_event_idUUID | nullObligatoireAppend-only audit event ID, or null for a no-op.
source_revisionintegerFacultatifSource revision on a restore result.
replayedbooleanObligatoireTrue when an exact Idempotency-Key retry replayed this result.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_admin_required403FacultatifThe operation requires a JWT user who is a workspace owner/admin or explicit project admin. API keys cannot perform it.
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.
invalid_json_body400FacultatifThe body is not one JSON value, contains unknown fields, or has invalid field types.
request_body_too_large413FacultatifThe JSON request exceeds the route's byte limit.
invalid_idempotency_key400FacultatifAn API-key command omitted Idempotency-Key or the trimmed value exceeds 255 characters.
idempotency_mismatch409FacultatifThe same actor already used this Idempotency-Key for different canonical command input.
if_match_required428FacultatifIf-Match is required for this page command.
invalid_if_match400FacultatifIf-Match is not the exact strong ETag for this page.
revision_conflict412FacultatifThe page has changed. The error details include expected_revision, current_revision, and current_etag; the response ETag is current.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN"   -H "Content-Type: application/json"   -H 'If-Match: "wiki-page:d2600000-0000-0000-0000-000000000201:rev:2"'   -d '{}'   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/unarchive

Exemple de réponse

{
  "outcome": "applied",
  "code": "wiki_page_unarchived",
  "page": {
    "id": "d2600000-0000-0000-0000-000000000201",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "revision": 3,
    "archived_at": null
  },
  "audit_event_id": "d2600000-0000-0000-0000-000000000504",
  "replayed": false
}
GET/api/projects/{projectId}/wiki/pages/{pageId}/revisionsList wiki page revisionsJeton utilisateur ou clé API

Returns newest-first immutable revision metadata without Markdown bodies. The page must still exist, including when archived.

Authentification: dual · Scopes: wiki:read

# GET /api/projects/{projectId}/wiki/pages/{pageId}/revisions

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.

Paramètres de requête

ChampType / statutObligatoireDescription
limitintegerFacultatifMaximum revision summaries, from 1 through 100. (Par défaut: 50)
offsetintegerFacultatifZero-based revision offset, from 0 through 10000. (Par défaut: 0)

Corps de réponse

ChampType / statutObligatoireDescription
revisionsWikiRevisionSummary[]ObligatoireRows with id, project_id, page_id, revision, revision_kind, restored_from_revision, title, slug, filename, archived_at, actor fields, and recorded_at; body_markdown is omitted.
page_idUUIDObligatoireRequested page UUID.
limitintegerObligatoireApplied limit.
offsetintegerObligatoireApplied offset.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.
invalid_revision_query400Facultatiflimit or offset is outside the accepted range.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   "http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/revisions?limit=50&offset=0"

Exemple de réponse

{
  "revisions": [
    {
      "id": "d2600000-0000-0000-0000-000000000601",
      "project_id": "b0000000-0000-0000-0000-000000000001",
      "page_id": "d2600000-0000-0000-0000-000000000201",
      "revision": 2,
      "revision_kind": "updated",
      "restored_from_revision": null,
      "title": "Incident response plan",
      "slug": "incident-response",
      "filename": "runbooks/incident-response.md",
      "archived_at": null,
      "actor_kind": "api_key",
      "actor_api_key_id": "d2600000-0000-0000-0000-000000000401",
      "actor_display": "d2600000-0000-0000-0000-000000000401",
      "recorded_at": "2026-08-16T10:30:00Z"
    }
  ],
  "page_id": "d2600000-0000-0000-0000-000000000201",
  "limit": 50,
  "offset": 0
}
GET/api/projects/{projectId}/wiki/pages/{pageId}/revisions/{revision}Get a wiki page revisionJeton utilisateur ou clé API

Returns one immutable revision snapshot, including its Markdown body. Revision is a canonical decimal integer from 1 through 9007199254740991; signs, leading zeroes, fractions, and out-of-range values are not accepted.

Authentification: dual · Scopes: wiki:read

# GET /api/projects/{projectId}/wiki/pages/{pageId}/revisions/{revision}

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.
revisionintegerObligatoireCanonical positive revision number, without leading zeroes.

Corps de réponse

ChampType / statutObligatoireDescription
revisionWikiRevisionObligatoireImmutable snapshot with id, project_id, page_id, revision, revision_kind, restored_from_revision, title, slug, filename, body_markdown, archived_at, actor fields, and recorded_at.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.
wiki_revision_not_found404FacultatifThe revision path is invalid or that revision does not exist for this page.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/revisions/1

Exemple de réponse

{
  "revision": {
    "id": "d2600000-0000-0000-0000-000000000601",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "page_id": "d2600000-0000-0000-0000-000000000201",
    "revision": 1,
    "revision_kind": "created",
    "restored_from_revision": null,
    "title": "Incident response",
    "slug": "incident-response",
    "filename": "runbooks/incident-response.md",
    "body_markdown": "# Incident response\n",
    "archived_at": null,
    "actor_kind": "user",
    "actor_user_id": "d2600000-0000-0000-0000-000000000301",
    "actor_display": "d2600000-0000-0000-0000-000000000301",
    "recorded_at": "2026-08-16T10:00:00Z"
  }
}
POST/api/projects/{projectId}/wiki/pages/{pageId}/restoreRestore a wiki page revisionJeton utilisateur ou clé API

Copies one immutable snapshot's title, slug, filename, and Markdown into a new page-head revision under exact ETag concurrency. API keys need both wiki:read and wiki:write because successful and no-op responses include the current page body. Restore is available on active or archived pages, but it does not change archived_at. An identical snapshot is a wiki_page_unchanged no-op. The JSON body limit is 1 KiB.

Authentification: dual · Scopes: wiki:read wiki:write

# POST /api/projects/{projectId}/wiki/pages/{pageId}/restore

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.

En-têtes de requête

ChampType / statutObligatoireDescription
If-Matchstrong ETagObligatoireExact current page ETag: "wiki-page:{pageId}:rev:{revision}". Weak tags, *, lists, another page ID, and non-canonical revision numbers are rejected.
Idempotency-KeystringFacultatifRequired for API-key commands and optional for JWT commands. After trimming, must be 1-255 Unicode characters. An exact retry by the same actor replays the saved result; reuse for different input returns idempotency_mismatch.

Corps de requête

ChampType / statutObligatoireDescription
source_revisionintegerObligatoireExisting positive revision to copy, up to 9007199254740991.

En-têtes de réponse

ChampType / statutObligatoireDescription
ETagstrong ETagObligatoireCurrent page version in the form "wiki-page:{pageId}:rev:{revision}". A revision_conflict response also returns the current value.

Corps de réponse

ChampType / statutObligatoireDescription
outcomeapplied | noopObligatoireWhether this command changed the page.
codestringObligatoireStable success/no-op code for this command.
page.idUUIDObligatoirePage UUID.
page.project_idUUIDObligatoireOwning project UUID.
page.titlestringObligatoireTrimmed title, 1-300 characters.
page.slugstringObligatoireLowercase kebab-case slug, at most 200 characters.
page.normalized_slugstringObligatoireStored normalized slug used for project uniqueness.
page.filenamestringObligatoireLowercase project-relative .md filename, 3-512 characters.
page.normalized_filenamestringObligatoireStored normalized filename used for project uniqueness.
page.body_markdownstringObligatoireCanonical Markdown head, at most 1 MiB; CRLF/CR is normalized to LF and non-empty content ends with LF.
page.revisionintegerObligatoireCurrent positive revision, up to 9007199254740991.
page.archived_atISO 8601 string | nullObligatoireArchive timestamp, or null while active.
page.created_actor_kinduser | api_key | systemObligatoirePrincipal kind that created the page.
page.created_actor_user_idUUIDFacultatifCreating user ID when actor_kind is user.
page.created_actor_api_key_idUUIDFacultatifCreating API key ID when actor_kind is api_key.
page.created_actor_displaystring | nullObligatoireStored display identity for the creating actor.
page.updated_actor_kinduser | api_key | systemObligatoirePrincipal kind that last changed the page.
page.updated_actor_user_idUUIDFacultatifLast updating user ID when actor_kind is user.
page.updated_actor_api_key_idUUIDFacultatifLast updating API key ID when actor_kind is api_key.
page.updated_actor_displaystring | nullObligatoireStored display identity for the last updating actor.
page.created_atISO 8601 stringObligatoireCreation timestamp.
page.updated_atISO 8601 stringObligatoireLast update timestamp.
audit_event_idUUID | nullObligatoireAppend-only audit event ID, or null for a no-op.
source_revisionintegerFacultatifSource revision on a restore result.
replayedbooleanObligatoireTrue when an exact Idempotency-Key retry replayed this result.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.
invalid_json_body400FacultatifThe body is not one JSON value, contains unknown fields, or has invalid field types.
request_body_too_large413FacultatifThe JSON request exceeds the route's byte limit.
invalid_idempotency_key400FacultatifAn API-key command omitted Idempotency-Key or the trimmed value exceeds 255 characters.
idempotency_mismatch409FacultatifThe same actor already used this Idempotency-Key for different canonical command input.
if_match_required428FacultatifIf-Match is required for this page command.
invalid_if_match400FacultatifIf-Match is not the exact strong ETag for this page.
revision_conflict412FacultatifThe page has changed. The error details include expected_revision, current_revision, and current_etag; the response ETag is current.
invalid_restore_input400Facultatifsource_revision is missing or not a canonical positive integer.
wiki_revision_not_found404FacultatifThe source revision does not exist for this page.
wiki_slug_conflict409FacultatifRestoring the snapshot would collide with another page slug.
wiki_filename_conflict409FacultatifRestoring the snapshot would collide with another page filename.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -H "Content-Type: application/json"   -H 'If-Match: "wiki-page:d2600000-0000-0000-0000-000000000201:rev:2"'   -H "Idempotency-Key: restore-incident-response-r1"   -d '{"source_revision":1}'   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/restore

Exemple de réponse

{
  "outcome": "applied",
  "code": "wiki_page_restored",
  "page": {
    "id": "d2600000-0000-0000-0000-000000000201",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "revision": 3,
    "title": "Incident response"
  },
  "audit_event_id": "d2600000-0000-0000-0000-000000000505",
  "source_revision": 1,
  "replayed": false
}
GET/api/projects/{projectId}/wiki/templatesList system wiki templatesJeton utilisateur ou clé API

Returns the read-only seeded system templates ordered by template_key after project access is checked. There are no template mutation routes.

Authentification: dual · Scopes: wiki:read

# GET /api/projects/{projectId}/wiki/templates

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.

Corps de réponse

ChampType / statutObligatoireDescription
templatesWikiTemplate[]ObligatoireSystem templates with id, template_key, name, description, body_markdown, version, is_system, created_at, and updated_at. Template Markdown is at most 256 KiB.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/templates

Exemple de réponse

{
  "templates": [
    {
      "id": "d2600000-0000-0000-0000-000000000701",
      "template_key": "runbook",
      "name": "Runbook",
      "description": "Operational procedure with verification and rollback.",
      "body_markdown": "# Runbook\n\n## Prerequisites\n\n## Procedure\n\n## Verification\n\n## Rollback\n",
      "version": 1,
      "is_system": true,
      "created_at": "2026-08-16T00:00:00Z",
      "updated_at": "2026-08-16T00:00:00Z"
    }
  ]
}
GET/api/projects/{projectId}/wiki/pages/{pageId}/export.mdExport page MarkdownJeton utilisateur ou clé API

Streams the current canonical Markdown bytes without rendering or normalization. Archived pages can be exported. The download filename is sanitized from the page filename and capped at 180 bytes.

Authentification: dual · Scopes: wiki:read

# GET /api/projects/{projectId}/wiki/pages/{pageId}/export.md

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.

En-têtes de réponse

ChampType / statutObligatoireDescription
ETagstrong ETagObligatoireCurrent page version in the form "wiki-page:{pageId}:rev:{revision}". A revision_conflict response also returns the current value.
Content-DispositionstringObligatoireattachment with safe filename and RFC 5987 filename* parameters.
Content-LengthintegerObligatoireExact Markdown byte count.
X-Content-Type-OptionsnosniffObligatoirePrevents browser MIME sniffing.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.

Types de contenu: application/json → text/markdown; charset=utf-8

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   --output incident-response.md   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/export.md

Exemple de réponse

# Incident response

Follow the project runbook.
GET/api/projects/{projectId}/wiki/pages/{pageId}/attachmentsList page attachmentsJeton utilisateur ou clé API

Returns ready image metadata and canonical wiki-attachment Markdown references for the page. Private storage bucket/path fields are never exposed.

Authentification: dual · Scopes: wiki:read

# GET /api/projects/{projectId}/wiki/pages/{pageId}/attachments

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.

Corps de réponse

ChampType / statutObligatoireDescription
attachmentsWikiAttachment[]ObligatoireReady attachment metadata in storage query order.
attachments[].idUUIDObligatoireAttachment UUID.
attachments[].project_idUUIDObligatoireOwning project UUID.
attachments[].page_idUUIDObligatoireOwning wiki page UUID.
attachments[].original_filenamestringObligatoireSanitized image filename, at most 180 bytes.
attachments[].content_typeimage/png | image/jpeg | image/webpObligatoireVerified media type detected from the bytes.
attachments[].size_bytesintegerObligatoireImage size from 1 byte through 8 MiB.
attachments[].sha256stringObligatoireLowercase SHA-256 hex digest.
attachments[].widthintegerObligatoireVerified width from 1 through 8000 pixels.
attachments[].heightintegerObligatoireVerified height from 1 through 8000 pixels.
attachments[].actor_kinduser | api_key | systemObligatoireUploading principal kind.
attachments[].actor_user_idUUID | nullObligatoireUploading user ID, when applicable.
attachments[].actor_api_key_idUUID | nullObligatoireUploading API key ID, when applicable.
attachments[].actor_displaystring | nullObligatoireStored display identity for the uploader.
attachments[].ready_atISO 8601 stringObligatoireTimestamp when storage and metadata became ready.
attachments[].created_atISO 8601 stringObligatoireCreation timestamp.
attachments[].markdownstringObligatoireCanonical ![alt](wiki-attachment:{attachmentId}) reference.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/attachments

Exemple de réponse

{
  "attachments": [
    {
      "id": "d2600000-0000-0000-0000-000000000401",
      "project_id": "b0000000-0000-0000-0000-000000000001",
      "page_id": "d2600000-0000-0000-0000-000000000201",
      "original_filename": "architecture.png",
      "content_type": "image/png",
      "size_bytes": 42137,
      "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "width": 1280,
      "height": 720,
      "actor_kind": "user",
      "actor_user_id": "d2600000-0000-0000-0000-000000000301",
      "actor_api_key_id": null,
      "actor_display": "d2600000-0000-0000-0000-000000000301",
      "ready_at": "2026-08-16T11:30:00Z",
      "created_at": "2026-08-16T11:30:00Z",
      "markdown": "![architecture](wiki-attachment:d2600000-0000-0000-0000-000000000401)"
    }
  ]
}
POST/api/projects/{projectId}/wiki/pages/{pageId}/attachmentsUpload a page imageJeton utilisateur ou clé API

Accepts exactly one multipart file field named file on an active page. The request is capped at 10 MiB and the file at 8 MiB. Only fully decodable PNG, JPEG, and WebP bytes are accepted; declared media type and filename extension must match, dimensions must be 1-8000 pixels and at most 16 megapixels total, and the sanitized filename is capped at 180 bytes. Each project is capped at 200 images and 50 MiB.

Authentification: dual · Scopes: wiki:write

# POST /api/projects/{projectId}/wiki/pages/{pageId}/attachments

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.

Corps de requête

ChampType / statutObligatoireDescription
filePNG | JPEG | WebP binaryObligatoireThe only multipart part. It must have a filename and an image/png, image/jpeg, or image/webp Content-Type matching its bytes and extension.

Corps de réponse

ChampType / statutObligatoireDescription
attachment.idUUIDObligatoireAttachment UUID.
attachment.project_idUUIDObligatoireOwning project UUID.
attachment.page_idUUIDObligatoireOwning wiki page UUID.
attachment.original_filenamestringObligatoireSanitized image filename, at most 180 bytes.
attachment.content_typeimage/png | image/jpeg | image/webpObligatoireVerified media type detected from the bytes.
attachment.size_bytesintegerObligatoireImage size from 1 byte through 8 MiB.
attachment.sha256stringObligatoireLowercase SHA-256 hex digest.
attachment.widthintegerObligatoireVerified width from 1 through 8000 pixels.
attachment.heightintegerObligatoireVerified height from 1 through 8000 pixels.
attachment.actor_kinduser | api_key | systemObligatoireUploading principal kind.
attachment.actor_user_idUUID | nullObligatoireUploading user ID, when applicable.
attachment.actor_api_key_idUUID | nullObligatoireUploading API key ID, when applicable.
attachment.actor_displaystring | nullObligatoireStored display identity for the uploader.
attachment.ready_atISO 8601 stringObligatoireTimestamp when storage and metadata became ready.
attachment.created_atISO 8601 stringObligatoireCreation timestamp.
attachment.markdownstringObligatoireCanonical ![alt](wiki-attachment:{attachmentId}) reference.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.
invalid_wiki_attachment_multipart400/415FacultatifThe request is not multipart/form-data or does not contain exactly one file part.
invalid_wiki_attachment400FacultatifThe image part is empty.
invalid_wiki_attachment_type415FacultatifThe file part has no valid declared Content-Type.
unsupported_wiki_attachment_type415FacultatifDetected bytes are not PNG, JPEG, or WebP.
wiki_attachment_type_mismatch415FacultatifDeclared image media type does not match detected bytes.
wiki_attachment_filename_type_mismatch400FacultatifFilename extension does not match the image type.
invalid_wiki_attachment_image400FacultatifImage bytes are malformed or truncated.
wiki_attachment_dimensions_exceeded400FacultatifImage width or height is outside 1-8000 pixels, or total pixels exceed 16 megapixels.
wiki_attachment_request_too_large413FacultatifThe multipart request exceeds 10 MiB.
wiki_attachment_too_large413FacultatifThe image exceeds 8 MiB.
wiki_page_archived409FacultatifArchived pages cannot receive attachments.
wiki_attachment_project_quota_exceeded409FacultatifThe project already has 200 images or 50 MiB of wiki image metadata.
wiki_attachment_storage_unavailable503FacultatifPrivate object storage could not accept the image.
wiki_attachment_metadata_reconciliation_pending503FacultatifThe generated attachment ID could not be conclusively re-queried after an ambiguous insert response. Storage is preserved and a delayed reconciliation row prevents cleanup if metadata later appears.

Types de contenu: multipart/form-data; boundary=... → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key"   -F "[email protected];type=image/png"   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/attachments

Exemple de réponse

{
  "attachment": {
    "id": "d2600000-0000-0000-0000-000000000401",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "page_id": "d2600000-0000-0000-0000-000000000201",
    "original_filename": "architecture.png",
    "content_type": "image/png",
    "size_bytes": 42137,
    "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "width": 1280,
    "height": 720,
    "actor_kind": "api_key",
    "actor_user_id": null,
    "actor_api_key_id": "d2600000-0000-0000-0000-000000000402",
    "actor_display": "d2600000-0000-0000-0000-000000000402",
    "ready_at": "2026-08-16T11:30:00Z",
    "created_at": "2026-08-16T11:30:00Z",
    "markdown": "![architecture](wiki-attachment:d2600000-0000-0000-0000-000000000401)"
  }
}
GET/api/projects/{projectId}/wiki/pages/{pageId}/attachments/{attachmentId}Create an attachment access URLJeton utilisateur ou clé API

The sole browser/agent access broker for the private project-wiki-images bucket. It verifies project, page, attachment, bucket, and object-path metadata before returning a client-facing signed download URL valid for 300 seconds. The endpoint returns JSON, not the image bytes.

Authentification: dual · Scopes: wiki:read

# GET /api/projects/{projectId}/wiki/pages/{pageId}/attachments/{attachmentId}

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.
attachmentIdUUIDObligatoireCanonical UUID of an attachment on the page.

Corps de réponse

ChampType / statutObligatoireDescription
attachment.idUUIDObligatoireAttachment UUID.
attachment.project_idUUIDObligatoireOwning project UUID.
attachment.page_idUUIDObligatoireOwning wiki page UUID.
attachment.original_filenamestringObligatoireSanitized image filename, at most 180 bytes.
attachment.content_typeimage/png | image/jpeg | image/webpObligatoireVerified media type detected from the bytes.
attachment.size_bytesintegerObligatoireImage size from 1 byte through 8 MiB.
attachment.sha256stringObligatoireLowercase SHA-256 hex digest.
attachment.widthintegerObligatoireVerified width from 1 through 8000 pixels.
attachment.heightintegerObligatoireVerified height from 1 through 8000 pixels.
attachment.actor_kinduser | api_key | systemObligatoireUploading principal kind.
attachment.actor_user_idUUID | nullObligatoireUploading user ID, when applicable.
attachment.actor_api_key_idUUID | nullObligatoireUploading API key ID, when applicable.
attachment.actor_displaystring | nullObligatoireStored display identity for the uploader.
attachment.ready_atISO 8601 stringObligatoireTimestamp when storage and metadata became ready.
attachment.created_atISO 8601 stringObligatoireCreation timestamp.
attachment.markdownstringObligatoireCanonical ![alt](wiki-attachment:{attachmentId}) reference.
download_urlURLObligatoireShort-lived signed private-storage URL.
expires_atISO 8601 stringObligatoireApproximate UTC expiry timestamp.
expires_in_secondsintegerObligatoireSigned URL lifetime; always 300.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.
wiki_attachment_not_found404FacultatifThe attachment ID is invalid or does not belong to this page.
wiki_attachment_unavailable503FacultatifThe attachment operation is temporarily unavailable.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/attachments/d2600000-0000-0000-0000-000000000401

Exemple de réponse

{
  "attachment": {
    "id": "d2600000-0000-0000-0000-000000000401",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "page_id": "d2600000-0000-0000-0000-000000000201",
    "original_filename": "architecture.png",
    "content_type": "image/png",
    "size_bytes": 42137,
    "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "width": 1280,
    "height": 720,
    "actor_kind": "user",
    "actor_user_id": "d2600000-0000-0000-0000-000000000301",
    "actor_api_key_id": null,
    "actor_display": "d2600000-0000-0000-0000-000000000301",
    "ready_at": "2026-08-16T11:30:00Z",
    "created_at": "2026-08-16T11:30:00Z",
    "markdown": "![architecture](wiki-attachment:d2600000-0000-0000-0000-000000000401)"
  },
  "download_url": "http://localhost:54421/storage/v1/object/sign/project-wiki-images/...",
  "expires_at": "2026-08-16T11:35:00Z",
  "expires_in_seconds": 300
}
DELETE/api/projects/{projectId}/wiki/pages/{pageId}/attachments/{attachmentId}Delete a wiki attachmentJeton utilisateur

JWT-admin-only destructive removal. API keys are rejected regardless of scope. A database trigger serializes the operation and returns wiki_attachment_in_use while current or immutable historical Markdown references the attachment. Otherwise metadata is deleted first and the private object path is durably queued in that transaction; storage is then removed and the queue row finalized.

Authentification: jwt_only · Scopes: —

# DELETE /api/projects/{projectId}/wiki/pages/{pageId}/attachments/{attachmentId}

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.
pageIdUUIDObligatoireCanonical UUID of a wiki page in the project.
attachmentIdUUIDObligatoireCanonical UUID of an attachment on the page.

Corps de réponse

ChampType / statutObligatoireDescription
deletedbooleanObligatoireTrue after object and metadata deletion.
attachment.idUUIDObligatoireAttachment UUID.
attachment.project_idUUIDObligatoireOwning project UUID.
attachment.page_idUUIDObligatoireOwning wiki page UUID.
attachment.original_filenamestringObligatoireSanitized image filename, at most 180 bytes.
attachment.content_typeimage/png | image/jpeg | image/webpObligatoireVerified media type detected from the bytes.
attachment.size_bytesintegerObligatoireImage size from 1 byte through 8 MiB.
attachment.sha256stringObligatoireLowercase SHA-256 hex digest.
attachment.widthintegerObligatoireVerified width from 1 through 8000 pixels.
attachment.heightintegerObligatoireVerified height from 1 through 8000 pixels.
attachment.actor_kinduser | api_key | systemObligatoireUploading principal kind.
attachment.actor_user_idUUID | nullObligatoireUploading user ID, when applicable.
attachment.actor_api_key_idUUID | nullObligatoireUploading API key ID, when applicable.
attachment.actor_displaystring | nullObligatoireStored display identity for the uploader.
attachment.ready_atISO 8601 stringObligatoireTimestamp when storage and metadata became ready.
attachment.created_atISO 8601 stringObligatoireCreation timestamp.
attachment.markdownstringObligatoireCanonical ![alt](wiki-attachment:{attachmentId}) reference.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_admin_required403FacultatifThe operation requires a JWT user who is a workspace owner/admin or explicit project admin. API keys cannot perform it.
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_page_not_found404FacultatifThe page ID is invalid or no matching page exists in this project.
wiki_attachment_not_found404FacultatifThe attachment ID is invalid or does not belong to this page.
wiki_attachment_unavailable503FacultatifThe attachment operation is temporarily unavailable.
wiki_attachment_in_use409FacultatifCurrent or immutable historical page content still references the attachment.
wiki_attachment_delete_metadata_failed503FacultatifThe database could not delete attachment metadata; storage is untouched.
wiki_attachment_delete_reconciliation_pending503FacultatifThe metadata-delete response was ambiguous. Storage is untouched and any committed deletion remains durably queued.
wiki_attachment_delete_cleanup_pending503FacultatifMetadata was deleted but storage removal or queue finalization failed. The durable queue retries idempotent object removal; details reports completed phases.

Types de contenu: application/json → application/json

Exemple cURL

curl -X DELETE -H "Authorization: Bearer YOUR_JWT_TOKEN"   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/pages/d2600000-0000-0000-0000-000000000201/attachments/d2600000-0000-0000-0000-000000000401

Exemple de réponse

{
  "deleted": true,
  "attachment": {
    "id": "d2600000-0000-0000-0000-000000000401",
    "project_id": "b0000000-0000-0000-0000-000000000001",
    "page_id": "d2600000-0000-0000-0000-000000000201",
    "original_filename": "architecture.png",
    "content_type": "image/png",
    "size_bytes": 42137,
    "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "width": 1280,
    "height": 720,
    "actor_kind": "user",
    "actor_user_id": "d2600000-0000-0000-0000-000000000301",
    "actor_api_key_id": null,
    "actor_display": "d2600000-0000-0000-0000-000000000301",
    "ready_at": "2026-08-16T11:30:00Z",
    "created_at": "2026-08-16T11:30:00Z",
    "markdown": "![architecture](wiki-attachment:d2600000-0000-0000-0000-000000000401)"
  }
}
GET/api/projects/{projectId}/wiki/export.zipExport the project wiki ZIPJeton utilisateur ou clé API

Builds and validates a deterministic current-state ZIP before streaming it. It contains active page heads only, ready image attachments, and root wiki-manifest.json version 1. Limits are 200 pages, 200 attachments, 500 entries, 50 MiB expanded, and 25 MiB output. Archived pages and their attachments are excluded; export rejects active pages whose stable links target an excluded page.

Authentification: dual · Scopes: wiki:read

# GET /api/projects/{projectId}/wiki/export.zip

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.

En-têtes de réponse

ChampType / statutObligatoireDescription
Content-DispositionstringObligatoireattachment filename project-{projectId}-wiki.zip.
Content-LengthintegerObligatoireExact completed ZIP byte count.
X-Content-Type-OptionsnosniffObligatoirePrevents browser MIME sniffing.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_archive_expanded_too_large413FacultatifAn entry or the complete ZIP exceeds 50 MiB expanded.
wiki_archive_page_limit413FacultatifThe archive or project contains more than 200 pages.
wiki_archive_attachment_limit413FacultatifThe archive or project contains more than 200 attachments.
wiki_archive_output_too_large413FacultatifThe generated ZIP exceeds the 25 MiB round-trip limit.
wiki_archive_attachment_corrupt409FacultatifStored attachment bytes do not match ready metadata.
wiki_archive_dangling_page_reference409FacultatifAn active page contains a stable link to a page excluded from the archive.
wiki_archive_storage_unavailable503FacultatifAn attachment could not be downloaded for export.

Types de contenu: application/json → application/zip

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key"   --output project-wiki.zip   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/export.zip

Exemple de réponse

Binary ZIP bytes beginning with PK (0x50 0x4b).
POST/api/projects/{projectId}/wiki/importImport a project wiki ZIPJeton utilisateur

JWT-admin-only import of the version-1 current-state archive contract. API keys are rejected regardless of scope. The multipart request must contain exactly one application/zip file field named file. Limits are 25 MiB compressed plus 1 MiB multipart overhead, 50 MiB expanded, 500 entries, 200 pages, 200 attachments, 100:1 compression, 1 MiB per Markdown page, and 8 MiB per image. Import creates new destination IDs and revision 1 pages; image references are rewritten. Exact Idempotency-Key retries are replayed by archive SHA-256.

Authentification: jwt_only · Scopes: —

# POST /api/projects/{projectId}/wiki/import

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdUUIDObligatoireCanonical UUID of the project that owns the independent wiki.

En-têtes de requête

ChampType / statutObligatoireDescription
Idempotency-KeystringFacultatifRequired for API-key commands and optional for JWT commands. After trimming, must be 1-255 Unicode characters. An exact retry by the same actor replays the saved result; reuse for different input returns idempotency_mismatch.

Corps de requête

ChampType / statutObligatoireDescription
fileapplication/zip binaryObligatoireThe only multipart part. The ZIP must contain root wiki-manifest.json version 1, pages/{filename} entries, and attachments/{sourceAttachmentId}/{filename} entries exactly referenced by the manifest.

Corps de réponse

ChampType / statutObligatoireDescription
outcomeappliedObligatoireSuccessful import outcome.
codewiki_archive_importedObligatoireStable success code.
project_idUUIDObligatoireDestination project UUID.
archive_sha256stringObligatoireSHA-256 of the uploaded ZIP bytes.
page_countintegerObligatoireNumber of created pages.
attachment_countintegerObligatoireNumber of created attachments.
pagesWikiArchiveImportPage[]ObligatoireMappings with source_id, destination id, title, slug, filename, source_revision, revision (1), and audit_event_id.
attachmentsWikiArchiveImportAttachment[]ObligatoireMappings with source_id, destination id, destination page_id, and private object path.
replayedbooleanObligatoireTrue for an exact saved retry.

Codes d’erreur

ChampType / statutObligatoireDescription
project_not_found404FacultatifThe project ID is invalid or the project does not exist.
project_access_denied403FacultatifThe JWT user cannot access the project or the API key is bound to another project.
authentication_required401FacultatifThe authenticated JWT user could not be identified.
wiki_admin_required403FacultatifThe operation requires a JWT user who is a workspace owner/admin or explicit project admin. API keys cannot perform it.
invalid_idempotency_key400FacultatifAn API-key command omitted Idempotency-Key or the trimmed value exceeds 255 characters.
idempotency_mismatch409FacultatifThe same actor already used this Idempotency-Key for different canonical command input.
invalid_wiki_archive400FacultatifThe ZIP is malformed, truncated, or fails CRC/length validation.
invalid_wiki_archive_manifest400Facultatifwiki-manifest.json is not the exact valid version-1 schema.
wiki_archive_manifest_missing400Facultatifwiki-manifest.json is absent from the ZIP root.
unsupported_wiki_archive_version400FacultatifThe manifest version is not 1.
unsafe_wiki_archive_path400FacultatifAn entry path is absolute, non-canonical, non-ASCII, or traverses directories.
duplicate_wiki_archive_path400FacultatifTwo ZIP paths normalize to the same case-insensitive path.
unsupported_wiki_archive_entry400FacultatifAn entry is encrypted, not a regular file, or uses unsupported compression.
nested_wiki_archive400FacultatifThe ZIP contains another archive file.
invalid_wiki_archive_page400FacultatifA page manifest entry or its canonical Markdown metadata is invalid.
wiki_archive_page_missing400FacultatifA manifest page path is absent from the ZIP.
invalid_wiki_archive_attachment400FacultatifAn attachment manifest entry, filename, media type, or metadata is invalid.
wiki_archive_attachment_missing400FacultatifA manifest attachment path is absent from the ZIP.
wiki_archive_attachment_size_mismatch400FacultatifAttachment bytes do not match the manifest size.
wiki_archive_attachment_hash_mismatch400FacultatifAttachment bytes do not match the manifest SHA-256.
invalid_wiki_archive_markdown400FacultatifA Markdown entry is not valid UTF-8 or contains NUL.
wiki_archive_page_collision409FacultatifImported page IDs, slugs, filenames, or paths collide.
wiki_archive_id_collision409FacultatifManifest page and attachment IDs collide.
wiki_archive_attachment_collision409FacultatifManifest attachment paths collide.
wiki_archive_compressed_too_large413FacultatifThe ZIP exceeds 25 MiB compressed.
wiki_archive_expanded_too_large413FacultatifAn entry or the complete ZIP exceeds 50 MiB expanded.
wiki_archive_compression_ratio413FacultatifAn entry or the complete ZIP exceeds a 100:1 expansion ratio.
wiki_archive_entry_limit413FacultatifThe ZIP does not contain 1-500 regular file entries.
wiki_archive_page_limit413FacultatifThe archive or project contains more than 200 pages.
wiki_archive_attachment_limit413FacultatifThe archive or project contains more than 200 attachments.
wiki_archive_markdown_too_large413FacultatifOne imported Markdown page exceeds 1 MiB.
wiki_archive_output_too_large413FacultatifThe generated ZIP exceeds the 25 MiB round-trip limit.
invalid_wiki_archive_multipart400/415FacultatifThe request is not the exact one-file application/zip multipart contract.
unexpected_wiki_archive_entry400FacultatifThe ZIP has a file not referenced by the manifest.
wiki_attachment_project_quota_exceeded409FacultatifImport would exceed the destination project's 200-image or 50 MiB wiki quota.
wiki_archive_storage_unavailable503FacultatifAttachment staging failed and completed cleanup succeeded.
wiki_archive_staging_cleanup_pending503FacultatifAttachment staging failed and storage cleanup remains pending.
wiki_archive_database_cleanup_pending503FacultatifPublication failed and staged-object cleanup remains pending.
wiki_archive_replay_cleanup_pending503FacultatifReplay succeeded but newly staged unused objects could not be removed.

Types de contenu: multipart/form-data; boundary=... → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN"   -H "Idempotency-Key: import-project-wiki-2026-08-16"   -F "[email protected];type=application/zip"   http://localhost:8080/api/projects/b0000000-0000-0000-0000-000000000001/wiki/import

Exemple de réponse

{
  "outcome": "applied",
  "code": "wiki_archive_imported",
  "project_id": "b0000000-0000-0000-0000-000000000001",
  "archive_sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
  "page_count": 1,
  "attachment_count": 1,
  "pages": [
    {
      "source_id": "d2600000-0000-0000-0000-000000000201",
      "id": "d2600000-0000-0000-0000-000000000801",
      "title": "Incident response",
      "slug": "incident-response",
      "filename": "runbooks/incident-response.md",
      "source_revision": 3,
      "revision": 1,
      "audit_event_id": "d2600000-0000-0000-0000-000000000802"
    }
  ],
  "attachments": [
    {
      "source_id": "d2600000-0000-0000-0000-000000000401",
      "id": "d2600000-0000-0000-0000-000000000803",
      "page_id": "d2600000-0000-0000-0000-000000000801",
      "path": "b0000000-0000-0000-0000-000000000001/d2600000-0000-0000-0000-000000000801/d2600000-0000-0000-0000-000000000803/architecture.png"
    }
  ],
  "replayed": false
}

Agent App Control

Durable human approval for high-impact project actions requested by external coding agents.

POST/api/projects/{projectId}/app-control/requestsRequest approval for a high-impact actionJeton utilisateur ou clé API

A project API key submits an exact typed action. BernOps stores only a request hash and safe resource summary; no domain mutation occurs.

Authentification: dual · Scopes: —

# POST /api/projects/{projectId}/app-control/requests

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireAPI key's project UUID.

En-têtes de requête

ChampType / statutObligatoireDescription
Idempotency-KeystringObligatoireStable logical-request identity. Reuse only for an exact retry.

Corps de requête

ChampType / statutObligatoireDescription
operationstringObligatoireAllowlisted high-impact app-control operation.
callobjectObligatoireExact typed params, query, body, and mutation preconditions for the operation.

Corps de réponse

ChampType / statutObligatoireDescription
request_idstringObligatoireDurable approval request UUID.
project_idstringObligatoireProject derived from the API key or stored request.
operationstringObligatoireHigh-impact operation awaiting or using approval.
safe_summaryobjectObligatoireServer-derived operation and resource IDs; never contains the request body.
statusstringObligatoirepending, approved, denied, executing, completed, failed, or expired.
expires_atstringObligatoireApproval expiry timestamp.
approval_pathstringObligatoireStatic browser route where a project administrator reviews the action.

Codes d’erreur

ChampType / statutObligatoireDescription
app_control_approval_not_required400FacultatifThe operation is routine and must use its normal endpoint.
app_control_insufficient_scope403FacultatifThe key lacks the operation's existing scope.
app_control_idempotency_mismatch409FacultatifThe idempotency key was reused for a different action.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer $BERNOPS_API_KEY" \
  -H "Idempotency-Key: approval-delete-label-v1" -H "Content-Type: application/json" \
  -d '{"operation":"label.delete","call":{"params":{"labelId":"LABEL_UUID"},"mutation":{"ifMatch":"\"7\""}}}' \
  http://localhost:8080/api/projects/PROJECT_UUID/app-control/requests

Exemple de réponse

{
  "request_id": "request-uuid",
  "project_id": "project-uuid",
  "operation": "label.delete",
  "safe_summary": {
    "operation": "label.delete",
    "resource_ids": {
      "labelId": "label-uuid"
    }
  },
  "status": "pending",
  "expires_at": "2026-08-28T18:00:00Z",
  "approval_path": "/projects/agents/approvals?projectId=project-uuid&requestId=request-uuid"
}
GET/api/app-control/requests/{requestId}Get approval statusJeton utilisateur ou clé API

Returns safe approval metadata to the originating API key or a project-visible JWT user.

Authentification: dual · Scopes: —

# GET /api/app-control/requests/{requestId}

Paramètres de chemin

ChampType / statutObligatoireDescription
requestIdstringObligatoireApproval request UUID.

Corps de réponse

ChampType / statutObligatoireDescription
request_idstringObligatoireDurable approval request UUID.
project_idstringObligatoireProject derived from the API key or stored request.
operationstringObligatoireHigh-impact operation awaiting or using approval.
safe_summaryobjectObligatoireServer-derived operation and resource IDs; never contains the request body.
statusstringObligatoirepending, approved, denied, executing, completed, failed, or expired.
expires_atstringObligatoireApproval expiry timestamp.
approval_pathstringObligatoireStatic browser route where a project administrator reviews the action.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer $BERNOPS_API_KEY" http://localhost:8080/api/app-control/requests/REQUEST_UUID

Exemple de réponse

{
  "request_id": "request-uuid",
  "status": "approved"
}
POST/api/app-control/requests/{requestId}/decisionApprove or deny an actionJeton utilisateur

A current project administrator makes the independent human decision. API keys cannot call this endpoint.

Authentification: jwt_only · Scopes: —

# POST /api/app-control/requests/{requestId}/decision

Paramètres de chemin

ChampType / statutObligatoireDescription
requestIdstringObligatoireApproval request UUID.

En-têtes de requête

ChampType / statutObligatoireDescription
Idempotency-KeystringObligatoireStable logical-request identity. Reuse only for an exact retry.

Corps de requête

ChampType / statutObligatoireDescription
approvedbooleanObligatoireTrue to approve, false to deny.

Corps de réponse

ChampType / statutObligatoireDescription
request_idstringObligatoireDurable approval request UUID.
project_idstringObligatoireProject derived from the API key or stored request.
operationstringObligatoireHigh-impact operation awaiting or using approval.
safe_summaryobjectObligatoireServer-derived operation and resource IDs; never contains the request body.
statusstringObligatoirepending, approved, denied, executing, completed, failed, or expired.
expires_atstringObligatoireApproval expiry timestamp.
approval_pathstringObligatoireStatic browser route where a project administrator reviews the action.

Codes d’erreur

ChampType / statutObligatoireDescription
app_control_admin_required403FacultatifThe user is not a project administrator.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer $JWT" -H "Idempotency-Key: decision-v1" \
  -H "Content-Type: application/json" -d '{"approved":true}' \
  http://localhost:8080/api/app-control/requests/REQUEST_UUID/decision

Exemple de réponse

{
  "request_id": "request-uuid",
  "status": "approved"
}
POST/api/app-control/requests/{requestId}/executeExecute an approved actionJeton utilisateur ou clé API

The same current API key resubmits the exact semantic action. BernOps rechecks scopes, project, approval, request hash, and domain preconditions before one replay-safe execution.

Authentification: dual · Scopes: —

# POST /api/app-control/requests/{requestId}/execute

Paramètres de chemin

ChampType / statutObligatoireDescription
requestIdstringObligatoireApproved request UUID.

Corps de requête

ChampType / statutObligatoireDescription
operationstringObligatoireAllowlisted high-impact app-control operation.
callobjectObligatoireExact typed params, query, body, and mutation preconditions for the operation.

Corps de réponse

ChampType / statutObligatoireDescription
resultobjectObligatoireCanonical result from the underlying domain command.

Codes d’erreur

ChampType / statutObligatoireDescription
app_control_approval_pending409FacultatifThe request still awaits a human decision.
app_control_request_denied403FacultatifThe request was denied.
app_control_request_expired410FacultatifThe request expired.
app_control_request_not_found404FacultatifKey, project, operation, or request hash did not match.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer $BERNOPS_API_KEY" -H "Content-Type: application/json" \
  -d '{"operation":"label.delete","call":{"params":{"labelId":"LABEL_UUID"},"mutation":{"ifMatch":"\"7\""}}}' \
  http://localhost:8080/api/app-control/requests/REQUEST_UUID/execute

Exemple de réponse

{
  "outcome": "applied",
  "code": "label_deleted"
}

Triggers

Manage cron-based triggers that automatically execute jobs on a schedule.

GET/api/projects/{projectId}/triggersList triggersJeton utilisateur ou clé API

Returns all triggers configured for the specified project.

Authentification: dual · Scopes: triggers:read

# GET /api/projects/{projectId}/triggers

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireTrigger UUID.
namestringObligatoireTrigger display name.
job_idstringObligatoireUUID of the associated job.
cron_expressionstringObligatoireCron schedule expression.
enabledbooleanObligatoireWhether the trigger is active.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/triggers

Exemple de réponse

[
  {
    "id": "trig-001",
    "name": "Nightly Login Test",
    "job_id": "e5f6a7b8-c9d0-1234-efab-345678901234",
    "cron_expression": "0 2 * * *",
    "enabled": true
  }
]
POST/api/projects/{projectId}/triggersCreate triggerJeton utilisateur ou clé API

Creates a new cron-based trigger that will execute the specified job on schedule. Project API keys need triggers:write.

Authentification: dual · Scopes: triggers:write

# POST /api/projects/{projectId}/triggers

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de requête

ChampType / statutObligatoireDescription
namestringObligatoireTrigger display name.
job_idstringObligatoireUUID of the job to execute.
cron_expressionstringObligatoireCron schedule expression (5-field).
enabledbooleanFacultatifWhether the trigger is active. Defaults to true.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireUUID of the newly created trigger.
namestringObligatoireTrigger name.
cron_expressionstringObligatoireCron schedule.
enabledbooleanObligatoireActive state.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name":"Hourly Smoke Test","job_id":"e5f6a7b8-...","cron_expression":"0 * * * *"}' \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/triggers

Exemple de réponse

{
  "id": "trig-002",
  "name": "Hourly Smoke Test",
  "cron_expression": "0 * * * *",
  "enabled": true,
  "created_at": "2026-04-04T14:00:00Z"
}
GET/api/triggers/{triggerId}Get triggerJeton utilisateur ou clé API

Returns the full details of a single trigger.

Authentification: dual · Scopes: triggers:read

# GET /api/triggers/{triggerId}

Paramètres de chemin

ChampType / statutObligatoireDescription
triggerIdstringObligatoireUUID of the trigger.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireTrigger UUID.
namestringObligatoireTrigger name.
job_idstringObligatoireAssociated job UUID.
cron_expressionstringObligatoireCron schedule expression.
enabledbooleanObligatoireWhether the trigger is active.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/triggers/trig-001

Exemple de réponse

{
  "id": "trig-001",
  "name": "Nightly Login Test",
  "job_id": "e5f6a7b8-c9d0-1234-efab-345678901234",
  "cron_expression": "0 2 * * *",
  "enabled": true,
  "created_at": "2026-03-15T09:00:00Z"
}
PUT/api/triggers/{triggerId}Update triggerJeton utilisateur ou clé API

Updates an existing trigger. Project API keys need triggers:write. Only provided fields are changed.

Authentification: dual · Scopes: triggers:write

# PUT /api/triggers/{triggerId}

Paramètres de chemin

ChampType / statutObligatoireDescription
triggerIdstringObligatoireUUID of the trigger.

Corps de requête

ChampType / statutObligatoireDescription
namestringFacultatifNew trigger name.
job_idstringFacultatifNew job UUID.
cron_expressionstringFacultatifNew cron schedule expression.
enabledbooleanFacultatifEnable or disable the trigger.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireTrigger UUID.
namestringObligatoireUpdated trigger name.
cron_expressionstringObligatoireUpdated cron schedule.
enabledbooleanObligatoireUpdated active state.
updated_atstringObligatoireISO 8601 update timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X PUT -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"cron_expression":"30 1 * * *"}' \
  http://localhost:8080/api/triggers/trig-001

Exemple de réponse

{
  "id": "trig-001",
  "name": "Nightly Login Test v2",
  "cron_expression": "30 1 * * *",
  "enabled": true,
  "updated_at": "2026-04-04T14:30:00Z"
}
DELETE/api/triggers/{triggerId}Delete triggerJeton utilisateur ou clé API

Permanently deletes a trigger. Project API keys need triggers:write. The associated job is not affected.

Authentification: dual · Scopes: triggers:write

# DELETE /api/triggers/{triggerId}

Paramètres de chemin

ChampType / statutObligatoireDescription
triggerIdstringObligatoireUUID of the trigger to delete.

Corps de réponse

ChampType / statutObligatoireDescription
messagestringObligatoireConfirmation message.

Types de contenu: application/json → application/json

Exemple cURL

curl -X DELETE -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/triggers/trig-001

Exemple de réponse

{
  "message": "Trigger deleted successfully."
}

Queues

Manage work queues for RPA automation. Queues hold items that can be processed by workers sequentially or in parallel.

GET/api/projects/{projectId}/queuesList queuesJeton utilisateur ou clé API

Returns all queues configured for the specified project.

Authentification: dual · Scopes: queues:read

# GET /api/projects/{projectId}/queues

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue UUID.
namestringObligatoireQueue display name.
descriptionstringFacultatifOptional queue description.
max_retriesnumberObligatoireMaximum retry attempts per item.
custom_statusesstring[]ObligatoireQueue-specific custom statuses.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/queues

Exemple de réponse

[
  {
    "id": "queue-001",
    "name": "Invoice Processing",
    "description": "Incoming invoices to be processed.",
    "max_retries": 3,
    "custom_statuses": [
      "blocked"
    ],
    "created_at": "2026-03-20T08:00:00Z"
  }
]
POST/api/projects/{projectId}/queuesCreate queueJeton utilisateur ou clé API

Creates a new work queue within the specified project.

Authentification: dual · Scopes: queues:write

# POST /api/projects/{projectId}/queues

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de requête

ChampType / statutObligatoireDescription
namestringObligatoireQueue display name.
descriptionstringFacultatifOptional description.
max_retriesnumberFacultatifMaximum retry attempts per item. Defaults to 3.
retry_delay_secondsnumberFacultatifDelay between retries in seconds. Defaults to 60.
deadline_secondsnumberFacultatifMaximum time in seconds before an in-progress item is considered timed out.
auto_trigger_job_idstringFacultatifUUID of a job to auto-trigger when items are added.
custom_statusesstring[]FacultatifAdditional queue-specific statuses allowed by the custom status endpoint.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireUUID of the newly created queue.
namestringObligatoireQueue name.
max_retriesnumberObligatoireConfigured max retries.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name":"Order Fulfillment","max_retries":5,"retry_delay_seconds":120,"custom_statuses":["blocked"]}' \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/queues

Exemple de réponse

{
  "id": "queue-002",
  "name": "Order Fulfillment",
  "max_retries": 5,
  "custom_statuses": [
    "blocked"
  ],
  "created_at": "2026-04-04T15:00:00Z"
}
GET/api/queues/{queueId}Get queueJeton utilisateur ou clé API

Returns the full details of a single queue, including its configuration.

Authentification: dual · Scopes: queues:read

# GET /api/queues/{queueId}

Paramètres de chemin

ChampType / statutObligatoireDescription
queueIdstringObligatoireUUID of the queue.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue UUID.
namestringObligatoireQueue name.
descriptionstringFacultatifQueue description.
max_retriesnumberObligatoireMaximum retries.
retry_delay_secondsnumberObligatoireDelay between retries.
deadline_secondsnumberFacultatifItem processing deadline.
custom_statusesstring[]ObligatoireQueue-specific custom statuses.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/queues/queue-001

Exemple de réponse

{
  "id": "queue-001",
  "name": "Invoice Processing",
  "description": "Incoming invoices to be processed.",
  "max_retries": 3,
  "retry_delay_seconds": 60,
  "deadline_seconds": 300,
  "custom_statuses": [
    "blocked"
  ],
  "created_at": "2026-03-20T08:00:00Z"
}
PUT/api/queues/{queueId}Update queueJeton utilisateur ou clé API

Updates an existing queue configuration. Only provided fields are changed.

Authentification: dual · Scopes: queues:write

# PUT /api/queues/{queueId}

Paramètres de chemin

ChampType / statutObligatoireDescription
queueIdstringObligatoireUUID of the queue.

Corps de requête

ChampType / statutObligatoireDescription
namestringFacultatifNew queue name.
descriptionstringFacultatifNew description.
max_retriesnumberFacultatifNew max retry count.
retry_delay_secondsnumberFacultatifNew retry delay.
deadline_secondsnumberFacultatifNew processing deadline.
auto_trigger_job_idstringFacultatifNew auto-trigger job UUID.
custom_statusesstring[]FacultatifReplace the queue-specific custom statuses.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue UUID.
namestringObligatoireUpdated queue name.
max_retriesnumberObligatoireUpdated max retries.
updated_atstringObligatoireISO 8601 update timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X PUT -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"max_retries":5,"custom_statuses":["blocked"]}' \
  http://localhost:8080/api/queues/queue-001

Exemple de réponse

{
  "id": "queue-001",
  "name": "Invoice Processing v2",
  "max_retries": 5,
  "custom_statuses": [
    "blocked"
  ],
  "updated_at": "2026-04-04T15:30:00Z"
}
DELETE/api/queues/{queueId}Delete queueJeton utilisateur ou clé API

Permanently deletes a queue and all its items. This action cannot be undone.

Authentification: dual · Scopes: queues:write

# DELETE /api/queues/{queueId}

Paramètres de chemin

ChampType / statutObligatoireDescription
queueIdstringObligatoireUUID of the queue to delete.

Corps de réponse

ChampType / statutObligatoireDescription
messagestringObligatoireConfirmation message.

Types de contenu: application/json → application/json

Exemple cURL

curl -X DELETE -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/queues/queue-001

Exemple de réponse

{
  "message": "Queue deleted successfully."
}
GET/api/queues/{queueId}/statsGet queue statsJeton utilisateur ou clé API

Returns aggregated statistics for a queue: item counts by status, throughput, and error rates.

Authentification: dual · Scopes: queues:read

# GET /api/queues/{queueId}/stats

Paramètres de chemin

ChampType / statutObligatoireDescription
queueIdstringObligatoireUUID of the queue.

Corps de réponse

ChampType / statutObligatoireDescription
totalnumberObligatoireTotal items in the queue.
status_countsobjectObligatoireCounts keyed by item status.
avg_processing_msnumberObligatoireAverage processing duration for completed items.
due_todaynumberObligatoireNew items due by the end of today.
retry_ratenumberObligatoirePercentage of items that have retried at least once.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/queues/queue-001/stats

Exemple de réponse

{
  "total": 250,
  "status_counts": {
    "new": 45,
    "in_progress": 3,
    "completed": 190,
    "failed": 12
  },
  "avg_processing_ms": 1830,
  "due_today": 8,
  "retry_rate": 4.8
}

Queue Items

Manage individual items within a work queue. Items flow through a fixed lifecycle: new, in_progress, completed, failed, or abandoned.

GET/api/queues/{queueId}/itemsList queue itemsJeton utilisateur ou clé API

Returns items in the specified queue, with optional filtering by status and reference.

Authentification: dual · Scopes: queues:read

# GET /api/queues/{queueId}/items

Paramètres de chemin

ChampType / statutObligatoireDescription
queueIdstringObligatoireUUID of the queue.

Paramètres de requête

ChampType / statutObligatoireDescription
statusstringFacultatifFilter by status: "new", "in_progress", "completed", "failed", "abandoned".
referencestringFacultatifFilter by reference identifier.
limitnumberFacultatifMaximum number of items to return. (Par défaut: 50)
offsetnumberFacultatifNumber of items to skip for pagination. (Par défaut: 0)

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue item UUID.
statusstringObligatoireItem status.
referencestringFacultatifExternal reference identifier.
prioritynumberObligatoireItem priority (higher = more urgent).
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  "http://localhost:8080/api/queues/queue-001/items?status=new&limit=20"

Exemple de réponse

[
  {
    "id": "item-001",
    "status": "new",
    "reference": "INV-2026-0042",
    "priority": 10,
    "created_at": "2026-04-04T10:00:00Z"
  }
]
POST/api/queues/{queueId}/itemsAdd queue itemJeton utilisateur ou clé API

Adds a single item to the queue for processing.

Authentification: dual · Scopes: queues:write

# POST /api/queues/{queueId}/items

Paramètres de chemin

ChampType / statutObligatoireDescription
queueIdstringObligatoireUUID of the queue.

Corps de requête

ChampType / statutObligatoireDescription
dataobjectObligatoireArbitrary JSON payload for the item.
referencestringFacultatifExternal reference identifier (e.g. invoice number).
prioritynumberFacultatifItem priority. Higher values are processed first.
tagsstring[]FacultatifTags for categorization and filtering.
due_datestringFacultatifISO 8601 deadline for processing this item.
defer_untilstringFacultatifISO 8601 timestamp before which the item should not be processed.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireUUID of the newly created item.
statusstringObligatoireInitial status ("new").
referencestringFacultatifReference identifier.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"data":{"invoice_id":"INV-2026-0043","amount":150.00},"reference":"INV-2026-0043","priority":5}' \
  http://localhost:8080/api/queues/queue-001/items

Exemple de réponse

{
  "id": "item-002",
  "status": "new",
  "reference": "INV-2026-0043",
  "created_at": "2026-04-04T15:00:00Z"
}
POST/api/queues/{queueId}/items/bulkBulk add queue itemsJeton utilisateur ou clé API

Adds multiple items to the queue in a single request. Each item follows the same schema as the single-add endpoint.

Authentification: dual · Scopes: queues:write

# POST /api/queues/{queueId}/items/bulk

Paramètres de chemin

ChampType / statutObligatoireDescription
queueIdstringObligatoireUUID of the queue.

Corps de requête

ChampType / statutObligatoireDescription
itemsQueueItemInput[]ObligatoireArray of items to add. Each item has: data (required), reference, priority, tags, due_date, defer_until.

Corps de réponse

ChampType / statutObligatoireDescription
creatednumberObligatoireNumber of items successfully created.
itemsQueueItem[]ObligatoireArray of created item summaries.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"data":{"order":"ORD-001"},"reference":"ORD-001"},{"data":{"order":"ORD-002"},"reference":"ORD-002"}]}' \
  http://localhost:8080/api/queues/queue-001/items/bulk

Exemple de réponse

{
  "created": 3,
  "items": [
    {
      "id": "item-003",
      "status": "new",
      "reference": "ORD-001"
    },
    {
      "id": "item-004",
      "status": "new",
      "reference": "ORD-002"
    },
    {
      "id": "item-005",
      "status": "new",
      "reference": "ORD-003"
    }
  ]
}
POST/api/queues/{queueId}/nextGet next queue itemJeton utilisateur ou clé API

Atomically fetches and locks the next available item from the queue. The item transitions to in_progress status.

Authentification: dual · Scopes: queues:execute

# POST /api/queues/{queueId}/next

Paramètres de chemin

ChampType / statutObligatoireDescription
queueIdstringObligatoireUUID of the queue.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue item UUID.
statusstringObligatoireUpdated status ("in_progress").
dataobjectObligatoireItem payload.
referencestringFacultatifExternal reference.
retry_countnumberObligatoireNumber of times this item has been retried.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/queues/queue-001/next

Exemple de réponse

{
  "id": "item-001",
  "status": "in_progress",
  "data": {
    "invoice_id": "INV-2026-0042",
    "amount": 99.99
  },
  "reference": "INV-2026-0042",
  "retry_count": 0
}
GET/api/queue-items/{itemId}Get queue itemJeton utilisateur ou clé API

Returns the full details of a single queue item, including its data payload and processing history.

Authentification: dual · Scopes: queues:read

# GET /api/queue-items/{itemId}

Paramètres de chemin

ChampType / statutObligatoireDescription
itemIdstringObligatoireUUID of the queue item.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue item UUID.
queue_idstringObligatoireUUID of the parent queue.
statusstringObligatoireCurrent item status.
dataobjectObligatoireItem payload.
referencestringFacultatifExternal reference.
retry_countnumberObligatoireNumber of retries attempted.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/queue-items/item-001

Exemple de réponse

{
  "id": "item-001",
  "queue_id": "queue-001",
  "status": "in_progress",
  "data": {
    "invoice_id": "INV-2026-0042",
    "amount": 99.99
  },
  "reference": "INV-2026-0042",
  "retry_count": 0,
  "created_at": "2026-04-04T10:00:00Z"
}
PUT/api/queue-items/{itemId}Update queue itemJeton utilisateur ou clé API

Updates an existing queue item's data, reference, priority, or tags.

Authentification: dual · Scopes: queues:write

# PUT /api/queue-items/{itemId}

Paramètres de chemin

ChampType / statutObligatoireDescription
itemIdstringObligatoireUUID of the queue item.

Corps de requête

ChampType / statutObligatoireDescription
dataobjectFacultatifUpdated item payload.
referencestringFacultatifUpdated reference identifier.
prioritynumberFacultatifUpdated priority.
tagsstring[]FacultatifUpdated tags.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue item UUID.
statusstringObligatoireCurrent item status.
updated_atstringObligatoireISO 8601 update timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X PUT -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"priority":20,"tags":["urgent"]}' \
  http://localhost:8080/api/queue-items/item-001

Exemple de réponse

{
  "id": "item-001",
  "status": "new",
  "updated_at": "2026-04-04T16:00:00Z"
}
POST/api/queue-items/{itemId}/statusSet queue item statusJeton utilisateur ou clé API

Sets a queue item to a default status or a custom status configured on the queue.

Authentification: dual · Scopes: queues:write

# POST /api/queue-items/{itemId}/status

Paramètres de chemin

ChampType / statutObligatoireDescription
itemIdstringObligatoireUUID of the queue item.

Corps de requête

ChampType / statutObligatoireDescription
statusstringObligatoireDefault or queue-defined custom status.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue item UUID.
statusstringObligatoireUpdated item status.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"status":"failed"}' \
  http://localhost:8080/api/queue-items/item-001/status

Exemple de réponse

{
  "id": "item-001",
  "status": "failed"
}
DELETE/api/queue-items/{itemId}Delete queue itemJeton utilisateur ou clé API

Permanently removes a queue item. Only allowed for items in new or terminal states.

Authentification: dual · Scopes: queues:write

# DELETE /api/queue-items/{itemId}

Paramètres de chemin

ChampType / statutObligatoireDescription
itemIdstringObligatoireUUID of the queue item to delete.

Corps de réponse

ChampType / statutObligatoireDescription
messagestringObligatoireConfirmation message.

Types de contenu: application/json → application/json

Exemple cURL

curl -X DELETE -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/queue-items/item-001

Exemple de réponse

{
  "message": "Queue item deleted successfully."
}
POST/api/queue-items/{itemId}/completeComplete queue itemJeton utilisateur ou clé API

Marks an in-progress queue item as successfully completed. Optionally attach output data.

Authentification: dual · Scopes: queues:execute

# POST /api/queue-items/{itemId}/complete

Paramètres de chemin

ChampType / statutObligatoireDescription
itemIdstringObligatoireUUID of the queue item.

Corps de requête

ChampType / statutObligatoireDescription
outputobjectFacultatifOptional output data from processing (results, generated files, etc.).

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue item UUID.
statusstringObligatoireUpdated status ("completed").
completed_atstringObligatoireISO 8601 completion timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"output":{"processed":true,"pdf_url":"https://storage.example.com/inv-42.pdf"}}' \
  http://localhost:8080/api/queue-items/item-001/complete

Exemple de réponse

{
  "id": "item-001",
  "status": "completed",
  "completed_at": "2026-04-04T16:05:00Z"
}
POST/api/queue-items/{itemId}/failFail queue itemJeton utilisateur ou clé API

Marks an in-progress queue item as failed. Optionally attach an error message. If retries remain, the item may be automatically requeued.

Authentification: dual · Scopes: queues:execute

# POST /api/queue-items/{itemId}/fail

Paramètres de chemin

ChampType / statutObligatoireDescription
itemIdstringObligatoireUUID of the queue item.

Corps de requête

ChampType / statutObligatoireDescription
error_messagestringFacultatifError message describing the failure.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue item UUID.
statusstringObligatoireUpdated status ("failed").
retry_countnumberObligatoireCurrent retry count.
max_retriesnumberObligatoireMax retries configured for the queue.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"error_message":"Timeout waiting for page load"}' \
  http://localhost:8080/api/queue-items/item-001/fail

Exemple de réponse

{
  "id": "item-001",
  "status": "failed",
  "retry_count": 2,
  "max_retries": 3
}
POST/api/queue-items/{itemId}/abandonAbandon queue itemJeton utilisateur ou clé API

Marks an in-progress queue item as abandoned without counting it as a retry.

Authentification: dual · Scopes: queues:execute

# POST /api/queue-items/{itemId}/abandon

Paramètres de chemin

ChampType / statutObligatoireDescription
itemIdstringObligatoireUUID of the queue item.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue item UUID.
statusstringObligatoireUpdated status ("abandoned").

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/queue-items/item-001/abandon

Exemple de réponse

{
  "id": "item-001",
  "status": "abandoned"
}
POST/api/queue-items/{itemId}/retryRetry queue itemJeton utilisateur ou clé API

Manually retries a failed queue item by resetting it to new status and incrementing the retry count.

Authentification: dual · Scopes: queues:execute

# POST /api/queue-items/{itemId}/retry

Paramètres de chemin

ChampType / statutObligatoireDescription
itemIdstringObligatoireUUID of the queue item.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireQueue item UUID.
statusstringObligatoireUpdated status ("new").
retry_countnumberObligatoireUpdated retry count.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer bo_live_your_api_key" \
  http://localhost:8080/api/queue-items/item-001/retry

Exemple de réponse

{
  "id": "item-001",
  "status": "new",
  "retry_count": 3
}

API Keys

Manage API keys for programmatic access. API keys provide an alternative to JWT tokens for automation and CI/CD integrations.

POST/api/projects/{projectId}/api-keysCreate API keyJeton utilisateur

Creates a new project-scoped API key. The raw key value is returned only once in the response.

Authentification: jwt_only · Scopes: —

# POST /api/projects/{projectId}/api-keys

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project that will own the key.

Corps de requête

ChampType / statutObligatoireDescription
namestringObligatoireDisplay name for the API key.
scopesstring[]ObligatoireArray of granted scopes such as "jobs:read", "runs:write", or "queues:execute".
expires_atstringFacultatifISO 8601 expiration timestamp. Omit for a non-expiring key.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireAPI key UUID.
keystringObligatoireThe raw API key value (bo_live_...). Shown only once.
namestringObligatoireKey display name.
scopesstring[]ObligatoireGranted scopes.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -X POST -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"CI Pipeline","scopes":["jobs:read","queues:execute"]}' \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/api-keys

Exemple de réponse

{
  "id": "key-001",
  "key": "bo_live_abc123def456ghi789jkl012mno345",
  "name": "CI Pipeline",
  "scopes": [
    "jobs:read",
    "queues:execute"
  ],
  "created_at": "2026-04-04T17:00:00Z"
}
GET/api/projects/{projectId}/api-keysList API keysJeton utilisateur

Returns all API keys for the specified project. The raw key value is never returned.

Authentification: jwt_only · Scopes: —

# GET /api/projects/{projectId}/api-keys

Paramètres de chemin

ChampType / statutObligatoireDescription
projectIdstringObligatoireUUID of the project.

Corps de réponse

ChampType / statutObligatoireDescription
idstringObligatoireAPI key UUID.
namestringObligatoireKey display name.
key_prefixstringObligatoireFirst 12 characters of the key for identification.
scopesstring[]ObligatoireGranted scopes.
last_used_atstringFacultatifISO 8601 timestamp of last use.
created_atstringObligatoireISO 8601 creation timestamp.

Types de contenu: application/json → application/json

Exemple cURL

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/projects/c3d4e5f6-a7b8-9012-cdef-123456789012/api-keys

Exemple de réponse

[
  {
    "id": "key-001",
    "name": "CI Pipeline",
    "key_prefix": "bo_live_abcd",
    "scopes": [
      "jobs:read",
      "queues:execute"
    ],
    "last_used_at": "2026-04-04T16:30:00Z",
    "created_at": "2026-04-04T17:00:00Z"
  }
]
DELETE/api/api-keys/{keyId}Revoke API keyJeton utilisateur

Permanently revokes an API key. Any requests using this key will immediately fail authentication.

Authentification: jwt_only · Scopes: —

# DELETE /api/api-keys/{keyId}

Paramètres de chemin

ChampType / statutObligatoireDescription
keyIdstringObligatoireUUID of the API key to revoke.

Corps de réponse

ChampType / statutObligatoireDescription
messagestringObligatoireConfirmation message.

Types de contenu: application/json → application/json

Exemple cURL

curl -X DELETE -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  http://localhost:8080/api/api-keys/key-001

Exemple de réponse

{
  "message": "API key revoked"
}