API Reference

Reference 15 min read Updated May 2026

Overview

The GrooveOS API lets you build on top of your team's shared memory: read and write memory items, search your team's knowledge, manage tasks and contacts, and query the entity graph — all programmatically. Every call carries your team scope; results never cross team boundaries.

Base URL: https://api.grooveos.app

This page documents the surface a developer on your team uses with an xbt_ token. Internal endpoints (Drive OAuth callbacks, GitHub webhooks, operator admin endpoints) are out of scope here — see the open-source repo for the full surface.

Authentication & headers

# All authenticated requests need:
Authorization: Bearer {your xbt_ token}
X-Team-Scope:  {your team slug}

Mint an xbt_ token from your profile

Sign in with GitHub at grooveos.app/account/teams/, then go to Settings → API tokens to create a token. Tokens are user-scoped — they inherit your team memberships and your role per team. Treat your token like a password: never commit it to version control. See Authentication for the full sign-in flow.

Quick start

# Test your token
curl https://api.grooveos.app/v1/me \
  -H "Authorization: Bearer $TOKEN"

# Search team memory
curl "https://api.grooveos.app/v1/memory/search?q=Q2+target" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"

Health

GET /v1/healthz

No auth required. Useful for monitoring or warm-up checks.

curl https://api.grooveos.app/v1/healthz

# Response (200 OK):
{"status": "ok", "version": "1.0.0"}

Profile

GET /v1/me

Returns the authenticated user, their team memberships, and which teams they are admin of.

curl https://api.grooveos.app/v1/me \
  -H "Authorization: Bearer $TOKEN"

# Response (200 OK):
{
  "id": "a1b2c3d4-...",
  "email": "alice@your-team.com",
  "github_login": "alicedev",
  "is_admin": false,
  "teams": ["your-team", "another-team"]
}

GET /v1/me/github

Returns the GitHub identity attached to your account — login, GitHub user ID, avatar, and the org-membership check used by the auto-join flow.

curl https://api.grooveos.app/v1/me/github \
  -H "Authorization: Bearer $TOKEN"

# Response:
{
  "github_username": "alicedev",
  "github_id": 8234567,
  "github_avatar_url": "https://avatars.githubusercontent.com/u/8234567",
  "is_org_member": true,
  "org": "your-org"
}

Teams

GET /v1/teams

Lists every team the authenticated user belongs to, with their role per team.

curl https://api.grooveos.app/v1/teams \
  -H "Authorization: Bearer $TOKEN"

# Response:
[
  {"scope": "your-team",    "name": "Your Team",     "role": "admin"},
  {"scope": "another-team", "name": "Another Team",  "role": "member"}
]

Memory

Memory items implement the 7-field tagging contract. Every write must include: team_scope, project_scope, visibility, confidence, truth_level, source, validation_status. Missing fields return HTTP 422.

POST /v1/memory/upsert

Create or update a memory item. If an item with the same source already exists in the team, it is updated in place (vector + metadata).

curl -X POST https://api.grooveos.app/v1/memory/upsert \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{
    "item": {
      "content": "The Q2 fundraising target is 2M€",
      "team_scope": "your-team",
      "project_scope": "fundraising",
      "visibility": "team",
      "confidence": 0.9,
      "truth_level": "WORKING",
      "source": "api:my-script",
      "validation_status": "pending"
    }
  }'

# Response (201 Created):
{"id": "mem_abc123...", "team_scope": "your-team", "truth_level": "WORKING"}

truth_level cannot be PATCHed directly

You can set truth_level when first upserting an item. To promote a fact to VALIDATED, CANONICAL, or PUBLIC afterwards, use Truth-level promotions below — a direct PATCH returns 405 by design.

GET /v1/memory/search

Semantic search across your team's memory. Filtered to your team scope automatically.

ParameterTypeDescription
qstringRequired. Natural-language query.
project_scopestringFilter by project slug.
truth_level_minstringMinimum truth level (default EPHEMERAL).
limitintResults per page (default 10, max 100).
curl "https://api.grooveos.app/v1/memory/search?q=fundraising+target&truth_level_min=WORKING&limit=5" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"

# Response:
[
  {
    "id": "mem_abc123...",
    "content": "The Q2 fundraising target is 2M€...",
    "score": 0.947,
    "team_scope": "your-team",
    "project_scope": "fundraising",
    "truth_level": "WORKING",
    "confidence": 0.9,
    "source": "librechat:conv_abc123:msg_7"
  }
]

GET /v1/memory/{item_id}

Fetch a single memory item. Returns 404 if the item is not in your team's scope.

PATCH /v1/memory/{item_id}

Update mutable fields: content, project_scope, visibility, confidence, validation_status, metadata. truth_level is rejected with 405 — use promotions instead.

curl -X PATCH https://api.grooveos.app/v1/memory/mem_abc123 \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{"confidence": 0.95, "validation_status": "human_reviewed"}'

DELETE /v1/memory/{item_id}

Hard-delete a memory item (removes Postgres row + Qdrant vector + graph node). Returns 204 No Content. For soft delete with 30-day recovery, see Brain Monitor.

Conversations & messages

POST /v1/conversations

Create a conversation record. Useful when you want to attach memory items and messages to a thread you control.

curl -X POST https://api.grooveos.app/v1/conversations \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Q2 Fundraising Strategy Session",
    "project_scope": "fundraising",
    "source": "api:my-script"
  }'

# Response (201 Created):
{
  "id": "conv_abc123",
  "title": "Q2 Fundraising Strategy Session",
  "team_scope": "your-team",
  "project_scope": "fundraising"
}

GET /v1/conversations

List the team's conversations. Paginate with limit (default 20) and offset; filter by project_scope.

GET /v1/conversations/{id}

Get conversation metadata. Use GET /v1/messages?conversation_id= for the message list.

POST /v1/messages

Append a message to a conversation. If conversation_id doesn't exist, it is created on the fly. Used by LibreChat and Open WebUI bridges, and by your own integrations.

curl -X POST https://api.grooveos.app/v1/messages \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "conv_abc123",
    "role": "user",
    "content": "What is our fundraising target for Q2?",
    "source": "api:my-script"
  }'

Truth-level promotions

Truth-level promotion is the formal workflow for advancing a fact from EPHEMERALWORKINGVALIDATEDCANONICALPUBLIC. Every promotion needs a justification; promotions to VALIDATED and above require team admin approval.

POST /v1/promotions

Submit a promotion request for a memory item.

curl -X POST https://api.grooveos.app/v1/promotions \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{
    "item_id": "mem_abc123",
    "target_level": "VALIDATED",
    "justification": "Confirmed in board meeting on 2026-05-01."
  }'

# Response (202 Accepted):
{
  "promotion_id": "promo_xyz",
  "item_id": "mem_abc123",
  "target_level": "VALIDATED",
  "status": "pending"
}

GET /v1/promotions

List pending promotions for your team. Team-admin only; supports ?status= and ?item_id= filters.

PATCH /v1/promotions/{promotion_id}

Approve or reject a pending promotion. Team-admin only. Approval updates the item's truth_level atomically.

curl -X PATCH https://api.grooveos.app/v1/promotions/promo_xyz \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{"decision": "approved", "note": "Verified in board minutes."}'

Brain Monitor

The Brain Monitor surface unifies seven entity types — memory_item, granola_note, conversation, message, team_message, task, contact — under one feed. These endpoints power the Brain Monitor page; you can call them yourself to build dashboards or polling loops.

GET /v1/brain/events

List entities for one team. Cursor-based pagination via since + cursor.

ParameterTypeDescription
entity_typestring?Filter to one of the seven types.
truth_levelstring?Filter on truth level.
sinceISO 8601Only rows after this timestamp (polling).
cursorstring?Next-page cursor from the previous response.
limitintPage size (default 50, max 200).
include_deletedbooleanInclude soft-deleted rows.
curl "https://api.grooveos.app/v1/brain/events?limit=20" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"

# Response:
{
  "items": [
    {
      "entity_type": "memory_item",
      "entity_id": "mem_abc",
      "team_scope": "your-team",
      "truth_level": "WORKING",
      "deleted_at": null,
      "source": "librechat:conv_abc123",
      "created_at": "2026-05-17T12:30:00Z",
      "preview": "Q2 planning confirmed for May 15..."
    }
  ],
  "next_cursor": "eyJj..."
}

PATCH /v1/brain/events/{entity_type}/{entity_id}

Inline-update the truth_level on any entity. Only the row's author or a team admin can call this; otherwise 403 with the locked wording "You can only edit items you created. Contact a team admin to modify items created by others."

curl -X PATCH "https://api.grooveos.app/v1/brain/events/memory_item/mem_abc" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{"truth_level": "VALIDATED"}'

DELETE /v1/brain/events/{entity_type}/{entity_id}

Soft-delete a row. The entity is hidden from feeds, searches, and AI context; it stays restorable for 30 days before being purged from Postgres, the vector store, and the entity graph.

curl -X DELETE "https://api.grooveos.app/v1/brain/events/task/task_xyz" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"
# 204 No Content

POST /v1/brain/events/{entity_type}/{entity_id}/restore

Restore a soft-deleted row within the 30-day window.

curl -X POST "https://api.grooveos.app/v1/brain/events/task/task_xyz/restore" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"

CRM Team & Enterprise

Contact directory, auto-populated from chats, meetings, and agents. Starter teams receive 403 on every CRM endpoint. See CRM for the user-facing guide.

GET /v1/crm/contacts

List the team's contacts.

curl "https://api.grooveos.app/v1/crm/contacts?limit=50&offset=0" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"

POST /v1/crm/contacts

Create a new contact. Email must be unique within the team (409 on conflict — use PUT for upsert).

curl -X POST "https://api.grooveos.app/v1/crm/contacts" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{"email":"alice@example.com","name":"Alice Martin","company":"Acme","role":"CTO"}'

PUT /v1/crm/contacts

Upsert by (team_scope, email). Idempotent — safe to call repeatedly. New non-null fields are added; existing fields are not blanked out.

PATCH /v1/crm/contacts/{contact_id}

Update an existing contact's fields.

DELETE /v1/crm/contacts/{contact_id}

Delete a contact (soft-delete with 30-day recovery, same model as Brain Monitor).

Tasks Team & Enterprise

Action-item tracking, auto-populated from meetings and agents. See Tasks for the user-facing guide.

GET /v1/tasks

List tasks. Supports ?status=, ?project_scope=, ?since= (ISO 8601, for polling), and ?limit= / ?offset=.

# All open tasks
curl "https://api.grooveos.app/v1/tasks?status=todo" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"

# Poll for new tasks since a timestamp
curl "https://api.grooveos.app/v1/tasks?since=2026-05-17T00:00:00Z" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"

POST /v1/tasks

Create a task manually. created_by is set to the authenticated user. Assignee must be a member of the same team.

curl -X POST "https://api.grooveos.app/v1/tasks" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Send deck to investor",
    "project_scope": "fundraising",
    "due_date": "2026-05-14",
    "visibility": "team",
    "confidence": 1.0,
    "truth_level": "WORKING",
    "validation_status": "pending"
  }'

GET /v1/tasks/{task_id}

Retrieve a single task by ID.

PATCH /v1/tasks/{task_id}

Update a task. Status changes produce a differentiated audit entry (task.status_changed with from/to fields).

curl -X PATCH "https://api.grooveos.app/v1/tasks/task_xyz" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{"status": "done"}'

DELETE /v1/tasks/{task_id}

Delete a task (logged to audit trail).

Meetings (Granola) Team & Enterprise

Once your team admin has connected Granola (see Meetings), meeting notes flow into memory automatically. If you use another meeting tool, you can push notes directly with the endpoint below.

POST /v1/integrations/granola/ingest

Push one meeting note. Writes a memory item + contacts + tasks atomically. Idempotent on note_id — pushing the same note twice is a no-op.

curl -X POST "https://api.grooveos.app/v1/integrations/granola/ingest" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team" \
  -H "Content-Type: application/json" \
  -d '{
    "note_id": "ext_note_abc123",
    "title": "Investor call — Series A",
    "summary": "Discussed Q2 targets. Alice will send deck by Friday.",
    "participants": [{"email":"alice@example.com","name":"Alice Martin"}],
    "action_items": [{"title":"Send deck","due_date":"2026-05-22"}],
    "created_at": "2026-05-17T10:00:00Z"
  }'

Entity graph

GET /v1/graph/neighbors

Query the temporal entity graph for relationships connected to a given entity in your team's scope. Each edge includes its validity window (valid_from / valid_until).

ParameterTypeDescription
entitystringRequired. Entity name (person, project, concept).
depthintTraversal depth, default 1 (max 3).
curl "https://api.grooveos.app/v1/graph/neighbors?entity=Alice" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"

# Response:
{
  "entity": "Alice",
  "team_scope": "your-team",
  "neighbors": [
    {
      "name": "Acme.Engineering",
      "relationship": "WAS_TECH_LEAD",
      "valid_from": "2025-01-15",
      "valid_until": "2025-05-31"
    }
  ]
}

System prompt

GET /v1/system-prompt

Returns your team's CANONICAL facts pre-formatted as plain text, ready to inject into an LLM system prompt. Use this so your own AI integrations always know your team's ground truth.

curl https://api.grooveos.app/v1/system-prompt \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Team-Scope: your-team"

# Response (200 OK, text/plain):
Team knowledge (CANONICAL, your-team):
- Q2 fundraising target: 2M€ (confirmed 2026-05-01)
- Tech lead: Alice (since 2025-06-01)
- Current runway: 18 months (as of 2026-04-15)

Error codes

CodeMeaningCommon causes
400Bad Requestteam_scope in payload doesn't match the X-Team-Scope header; malformed JSON.
401UnauthorizedMissing token; expired or revoked xbt_; invalid signature.
403ForbiddenNot a member of the requested team; non-admin attempting an admin-only action; Starter team calling a paid endpoint.
404Not FoundItem, conversation, promotion, contact, or task does not exist in this team's scope.
405Method Not AllowedAttempted to PATCH truth_level directly — use POST /v1/promotions.
409ConflictEmail already exists for the team (on POST /crm/contacts); duplicate integration registration.
422Unprocessable EntityMissing required tagging field on a memory item (one of the 7).
429Too Many RequestsRate limit exceeded — see below.

Every error response includes a detail field with a human-readable message:

{"detail": "Missing required field: truth_level. All memory items must carry the 7 tagging contract fields."}

Rate limits

PlanLimit
Free60 requests / minute
Team300 requests / minute
EnterpriseCustom limits

Building an agent or automation?

Background agents that continuously write memory items can hit the 300/min ceiling. Reach out at team@grooveos.app to discuss Enterprise rate limits.

SDK examples

Official SDKs are coming soon. Until then, the REST API works cleanly with any HTTP client.

Python

import requests

BASE = "https://api.grooveos.app"
TOKEN = "xbt_your_token_here"
TEAM  = "your-team"

def search_memory(query: str):
    response = requests.get(
        f"{BASE}/v1/memory/search",
        params={"q": query, "truth_level_min": "WORKING"},
        headers={
            "Authorization": f"Bearer {TOKEN}",
            "X-Team-Scope": TEAM,
        },
    )
    response.raise_for_status()
    return response.json()

results = search_memory("Q2 target")

JavaScript / TypeScript

const BASE = "https://api.grooveos.app";
const TOKEN = "xbt_your_token_here";
const TEAM  = "your-team";

async function searchMemory(query) {
  const url = new URL(`${BASE}/v1/memory/search`);
  url.searchParams.set("q", query);
  url.searchParams.set("truth_level_min", "WORKING");
  const res = await fetch(url, {
    headers: {
      "Authorization": `Bearer ${TOKEN}`,
      "X-Team-Scope": TEAM,
    },
  });
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
  return res.json();
}

const results = await searchMemory("Q2 target");

What's next