Skip to main content
The oobo CLI pushes commit attribution data (anchors) to the Oobo backend using an organization API key. This page documents the API that any self-hosted instance must implement. Base URL: https://api.oobo.ai (or your self-hosted URL)

Authentication

All CLI requests authenticate with an organization API key:
Authorization: Bearer sk-oobo-v1-<key>
API keys are created by an organization member via the Oobo web app (Settings > API Keys), or configured locally:
oobo auth login --key sk-oobo-v1-your_key
# or
export OOBO_SECRET_KEY=sk-oobo-v1-your_key

Endpoints

Health check

GET /health
No auth required. Response 200:
{ "status": "ok" }

Auth: Who am I

GET /api/v1/auth/me
Authorization: Bearer sk-oobo-v1-<key>
Response 200:
{
  "id": "usr_abc123",
  "email": "dev@company.com",
  "name": "Developer",
  "org_id": "org_xyz",
  "org_name": "Acme Corp"
}
Response 401:
{ "detail": "Invalid API key" }

Ingest anchor

Push a commit anchor to Oobo. Called automatically by the CLI on every git commit when sync is enabled.
POST /anchors/ingest
Authorization: Bearer sk-oobo-v1-<key>
Content-Type: application/json
Request body:
{
  "event": "git.commit",
  "timestamp": "2026-03-12T02:30:00Z",
  "oobo_version": "0.1.0",
  "project": {
    "name": "my-app",
    "git_remote": "github.com/user/my-app"
  },
  "anchor": {
    "commit_hash": "abc123def456789...",
    "branch": "main",
    "author": "Dev <dev@co.com>",
    "author_type": "assisted",
    "contributors": [
      { "name": "Dev <dev@co.com>", "role": "human" },
      { "name": "claude", "role": "agent", "model": "claude-sonnet-4" }
    ],
    "committed_at": 1773282899,
    "message": "feat: add auth flow",
    "files_changed": ["auth.js", "config.js"],
    "added": 35,
    "deleted": 0,
    "file_changes": [
      { "path": "auth.js", "added": 24, "deleted": 0, "attribution": "ai", "agent": "claude" },
      { "path": "config.js", "added": 11, "deleted": 0, "attribution": "human" }
    ],
    "ai_added": 24,
    "ai_deleted": 0,
    "human_added": 11,
    "human_deleted": 0,
    "ai_percentage": 68.57,
    "sessions": [
      {
        "session_id": "abc-123",
        "agent": "claude",
        "model": "claude-sonnet-4",
        "link_type": "explicit",
        "input_tokens": 15000,
        "output_tokens": 8000,
        "cache_read_tokens": 5000,
        "duration_secs": 120,
        "tool_calls": 5,
        "files_touched": ["auth.js"],
        "is_subagent": false,
        "is_estimated": false
      }
    ],
    "transparency_mode": "on"
  },
  "transcript": [
    { "role": "user", "text": "Add auth flow" },
    { "role": "assistant", "text": "I'll create the auth module..." }
  ]
}

Field reference

Top-level fields:
FieldTypeRequiredDescription
eventstringyesEvent type, e.g. git.commit
timestampstringnoISO 8601 timestamp
oobo_versionstringnoCLI version
projectobjectyesProject metadata
anchorobjectyesFull anchor data
transcriptarraynoOnly included when transparency_mode == "on"
project object:
FieldTypeRequiredDescription
namestringyesProject name
git_remotestringyesGit remote URL
anchor object:
FieldTypeRequiredDescription
commit_hashstringyesFull commit SHA
branchstringnoBranch name
authorstringnoAuthor in Name <email> format
author_typestringnoassisted, human, agent, or automated
contributorsarraynoList of contributors
committed_atintnoUnix timestamp
messagestringnoCommit message
files_changedarraynoList of changed file paths
addedintnoTotal lines added
deletedintnoTotal lines deleted
file_changesarraynoPer-file change details with attribution
ai_addedintnoLines added by AI
ai_deletedintnoLines deleted by AI
human_addedintnoLines added by humans
human_deletedintnoLines deleted by humans
ai_percentagefloatnoPercentage of code written by AI (0–100)
sessionsarraynoAI agent sessions linked to this commit
transparency_modestringno"on" or "off"
anchor.contributors[]:
FieldTypeRequiredDescription
namestringyesContributor name or agent name
rolestringyeshuman or agent
modelstringnoLLM model name (agents only)
anchor.file_changes[]:
FieldTypeRequiredDescription
pathstringyesFile path
addedintnoLines added in this file
deletedintnoLines deleted in this file
attributionstringnoai, human, or mixed
agentstringnoAgent name (when attribution is ai or mixed)
anchor.sessions[]:
FieldTypeRequiredDescription
session_idstringyesUnique session identifier
agentstringnoAgent name
modelstringnoLLM model name
link_typestringnoHow session was linked: explicit or inferred
input_tokensintnoInput token count
output_tokensintnoOutput token count
cache_read_tokensintnoCached tokens read
duration_secsfloatnoSession duration in seconds
tool_callsintnoNumber of tool calls
files_touchedarraynoFiles modified in this session
is_subagentboolnoWhether this is a sub-agent session
is_estimatedboolnoWhether token counts are estimated vs actual
transcript[]:
FieldTypeRequiredDescription
rolestringyesuser or assistant
textstringyesMessage content

Success response

{
  "success": true,
  "message": "Anchor ingested",
  "data": {
    "anchor_id": "550e8400-e29b-41d4-a716-446655440000",
    "commit_hash": "abc123def456789..."
  }
}

Error responses

StatusBodyCause
401{ "detail": "Missing or invalid Authorization header" }No Authorization: Bearer ... header
401{ "detail": "Invalid API key format" }Key doesn’t start with sk-oobo-v1-
401{ "detail": "Invalid API key" }Key not found or deleted
422Validation errorMissing required fields or wrong types
500{ "success": false, "message": "Failed to ingest anchor" }Server error

Duplicate handling

The server enforces a unique constraint on (git_remote, commit_hash). Pushing the same commit hash for the same remote twice results in a database error. The CLI handles this gracefully (treats as success).

Shares: Create

POST /api/v1/shares
Authorization: Bearer sk-oobo-v1-<key>
Content-Type: application/json
Publishes a redacted session. Request body is the full SharedSession JSON from oobo share. Response 201:
{
  "id": "shr_abc123",
  "url": "https://app.oobo.ai/s/shr_abc123",
  "expires_at": null
}

Shares: Get

GET /api/v1/shares/:id
Public shares require no auth; private shares require the owner’s key.

Shares: Delete

DELETE /api/v1/shares/:id
Authorization: Bearer sk-oobo-v1-<key>
Requires owner auth.

Shares: List

GET /api/v1/shares?limit=20&offset=0
Authorization: Bearer sk-oobo-v1-<key>
Lists all shares created by the authenticated user.

Error format

All error responses follow this structure:
{ "detail": "Human-readable error description" }
Or for ingestion errors:
{ "success": false, "message": "Human-readable error description" }

Self-hosted

Self-hosted instances must implement the endpoints above. Configure the CLI to point at your server:
oobo auth set-remote https://oobo.mycompany.com
Or in ~/.oobo/config.toml:
[server]
url = "https://oobo.mycompany.com"
api_key = "sk-oobo-v1-your_key"
sync = true

Example: curl

curl -X POST https://api.oobo.ai/anchors/ingest \
  -H "Authorization: Bearer sk-oobo-v1-YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "git.commit",
    "oobo_version": "0.1.0",
    "project": {
      "name": "my-app",
      "git_remote": "github.com/user/my-app"
    },
    "anchor": {
      "commit_hash": "abc123",
      "branch": "main",
      "author": "Dev <dev@co.com>",
      "author_type": "human",
      "contributors": [],
      "message": "fix: typo",
      "files_changed": ["readme.md"],
      "added": 1,
      "deleted": 1,
      "file_changes": [
        { "path": "readme.md", "added": 1, "deleted": 1, "attribution": "human" }
      ],
      "ai_added": 0,
      "ai_deleted": 0,
      "human_added": 1,
      "human_deleted": 1,
      "ai_percentage": 0.0,
      "sessions": [],
      "transparency_mode": "off"
    }
  }'