API Reference
The Objectuve API is a single GraphQL endpoint with real-time WebSocket subscriptions.
In-site GraphQL reference (auto-generated from rails_api/schema.graphql):
- GraphQL API Overview — endpoint, auth, categorized table of contents with current field/type counts
- Queries — all root query fields with arguments and return types
- Mutations — all root mutation fields with arguments and return types
- Types — all object types
- Enums · Inputs · Scalars
Field and type counts change frequently as the schema grows — see the "Contents" table on the GraphQL API Overview page for the current, auto-generated counts rather than a number hardcoded here.
For an interactive schema graph explorer, visit api-docs.objectuve.com (GraphQL Voyager).
Endpoints
| Protocol | URL | Purpose |
|---|---|---|
POST | /graphql | All queries, mutations, and batch operations |
WS | /cable | Real-time subscriptions (ActionCable) |
GET | /health | Detailed health check (DB, Redis, Sidekiq) — returns 200 or 503 |
GET | /up | Simple load balancer health check |
Authentication
Authentication is handled by Clerk. The Rails API does not issue JWTs — it only verifies them. Sign-in, sign-up, and OAuth happen client-side via the Clerk SDK; the backend validates the resulting RS256 JWT via JWKS on every request.
Include the Clerk JWT in every authenticated request:
SessionToken: <clerk-jwt>WARNING
The header is SessionToken (PascalCase). It is not Authorization: Bearer. See authentication.md for the full Clerk flow, JWKS verification, fallback auth, and demo login.
Post sign-in: syncUser
After Clerk completes authentication client-side, call the syncUser mutation to find-or-create the local user record and detect first sign-in for onboarding:
mutation {
syncUser {
user {
id
firstName
lastName
username
}
firstSignIn
errors
}
}firstSignIn is true on the user's very first authenticated request — use it to route into the onboarding wizard.
ID Convention
All IDs exposed by this API are publicId values — URL-safe base64 tokens generated on record creation. Internal integer IDs are never returned. Pass publicId values wherever a mutation or query requires an id or userId argument.
Batch Requests
The API supports batched GraphQL operations. Send an array of operation objects to /graphql:
[
{ "query": "query { goalCategories { id name } }" },
{ "query": "query { goalKinds { id name } }" }
]Real-time Subscriptions (WebSocket)
Connect to WS /cable using ActionCable. Two subscriptions are available:
subscription {
notificationUpdate(userId: "abc123XYZ") {
id
kind
content
acknowledged
}
}subscription {
aiRequestUpdate(requestId: "req_abc123") {
id
status
resultJson
errorCode
errorMessage
}
}aiRequestUpdate streams a single async AiRequest's status/result as Ai::DispatchAiRequestJob broadcasts it (v4.60 Phase 1, OBJ-3758) — see GraphQL Reference § Subscriptions and Data Models § Async AI Delivery. Backend-only as of Phase 1 — no mutation dispatches an AiRequest yet.
Interactive Documentation
| Tool | URL (local dev) | Description |
|---|---|---|
| Spectaql | http://localhost:3000/docs/ | Interactive API reference with examples, argument docs, and type explorer |
| Voyager | http://localhost:3000/docs/voyager.html | Visual schema graph — explore type relationships interactively |
Regenerating Documentation
Documentation is generated from schema.graphql which is dumped from the Rails GraphQL gem.
cd rails_api
# 1. Regenerate schema.graphql from Ruby type definitions
bundle exec rake graphql:schema:dump
# 2. Generate all docs (Voyager + Spectaql)
npm run generate:docs
# Or individually:
npm run generate:voyager # → public/docs/voyager.html
npm run generate:spectaql # → public/docs/index.htmlRun npm install if dependencies are not yet installed.
Key Operations Quick Reference
Authentication
| Operation | Type | Description |
|---|---|---|
syncUser | Mutation | Find-or-create the local user from the Clerk JWT and return firstSignIn for onboarding routing |
authzCheck | Query | Check whether the current user holds a permission (e.g. admin) |
Goals
| Operation | Type | Description |
|---|---|---|
goals | Query | List the current user's top-level goals |
goal | Query | Fetch a single goal by ID |
publicGoal | Query | Fetch a public goal (no auth required) |
addGoal | Mutation | Create a new goal |
updateGoal | Mutation | Update an existing goal |
addGoalEvent | Mutation | Log a progress event |
generateMilestones | Mutation | AI-generate sub-goal milestones |
Communities
| Operation | Type | Description |
|---|---|---|
communities | Query | List all or filtered communities |
communityFeed | Query | Paginated post feed for a community |
createCommunity | Mutation | Create a new community |
joinCommunity | Mutation | Join a community |
createCommunityPost | Mutation | Post an update to a community |
Habits & Progress
| Operation | Type | Description |
|---|---|---|
checkInHabit | Mutation | One-tap habit check-in for today |
useStreakFreeze | Mutation | Use a freeze to preserve a habit streak |
goalProgressData | Query | Progress chart data (events grouped by day/week/month, pace, streaks) |
unifiedFeed | Query | Paginated unified feed of ally, community, and own activity |
Accountability Partners
| Operation | Type | Description |
|---|---|---|
accountabilityPartner | Query | Fetch the current user's active accountability partner (or null) |
sendPartnerRequest | Mutation | Send an accountability partner request to an accepted ally |
acceptPartnerRequest | Mutation | Accept a pending partner request |
declinePartnerRequest | Mutation | Decline a pending partner request (no notification sent) |
endPartnership | Mutation | End an active accountability partnership |
Community Challenges
| Operation | Type | Description |
|---|---|---|
createCommunityChallenge | Mutation | Create a time-boxed challenge for a community |
joinCommunityChallenge | Mutation | Join an active or upcoming challenge as a participant |
leaveCommunityChallenge | Mutation | Leave a challenge (refunds participation, clears progress) |
communityChallengeLeaderboard | Query | Fetch leaderboard rankings for a challenge (paginated) |
Mood & Insights
| Operation | Type | Description |
|---|---|---|
addMoodLog | Mutation | Record a mood check-in |
getInsight | Mutation | AI insights on progress patterns |
getAdvice | Mutation | AI advice for a specific goal |
Async AI Delivery (v4.60 Phase 1)
| Operation | Type | Description |
|---|---|---|
aiRequest | Query | Fetch a single async AiRequest by id — the reconnect-recovery counterpart to aiRequestUpdate |
aiRequestUpdate | Subscription | Stream status/result updates for a single async AiRequest in real time |
Durable substrate shipped with nothing calling it yet (OBJ-3758) — see GraphQL Reference § Async AI Delivery and Data Models § Async AI Delivery.
Teams (Teams V1)
| Operation | Type | Description |
|---|---|---|
myTeam / teamHome / teamSettings | Query | The authenticated user's team, the TeamHomeView aggregate read, and the TeamSettingsView aggregate read |
teamInvitePreview | Query | Public, unauthenticated preview of an invite for /join-team/{code} |
createTeamInvite / revokeTeamInvite / acceptTeamInvite | Mutation | Create, revoke, or accept a team invite |
promoteTeamMember / removeTeamMember | Mutation | Change a member's role, or remove them from the team |
createSubCommunity / archiveSubCommunity / unarchiveSubCommunity / setDefaultSubCommunity | Mutation | Create or manage a team's sub-communities (rooms) |
joinSubCommunity / leaveSubCommunity | Mutation | Self-service join/leave for an open sub-community |
teamLeaderboard | Query | Ranked, opted-in leaderboard entries for a team or sub-community, scoped by weekly/monthly/all-time period |
setLeaderboardVisibility | Mutation | Self-service member opt-out/opt-in from the team leaderboard |
teamLeaderboardOptOutStats | Query | Admin-only raw opt-out counts per team (anti-metric — no percentage exposed) |
See GraphQL Reference § Teams — Sub-Communities, Membership & Invites for the full 15-mutation + 4-query surface (arguments, return shapes, error behavior), and § Leaderboards (Teams V1) for the points-engine query/mutation added in Phase 4.
AI Workforce API (Admin Only)
All AI Workforce queries and mutations require admin authentication (require_admin!).
Queries
| Query | Arguments | Returns | Description |
|---|---|---|---|
aiEmployees | — | [AiEmployeeType] | All employees with runs preloaded |
pendingArtifacts | — | [AiArtifactType] | Pending artifacts sorted by creation time |
aiEmployee | id: String! | AiEmployeeType | Employee detail with memories, runs, approval rate, promotion criteria |
aiRun | id: String! | AiRunType | Run detail with artifacts and execution log |
Mutations
| Mutation | Arguments | Returns | Description |
|---|---|---|---|
triggerAiRun | employeeId: String! | { run, errors } | Manually trigger an employee run |
pauseAiEmployee | employeeId: String!, active: Boolean! | { employee, errors } | Pause or resume an employee |
updateAiEmployee | employeeId: String!, name?, description?, taskPrompt?, monthlyBudgetCents?, modelPreference?, scheduleCron?, autonomyLevel?, confirmPromotion? | { employee, errors } | Update employee config or promote/demote autonomy |
approveAiArtifact | artifactId: String!, editedPayload?: String | { artifact, errors } | Approve artifact (triggers delivery) |
rejectAiArtifact | artifactId: String!, rejectionReason: String! | { artifact, errors } | Reject artifact with reason (min 10 chars) |
Webhook Endpoint
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /webhooks/ai-workforce | HMAC-SHA256 (X-Workforce-Signature) | Agent Runner posts run results |
AI Workforce Types
AiEmployeeType— employee config, budget, schedule, promotion criteria, memories, runsAiRunType— run status, tokens, cost, execution log, artifactsAiArtifactType— artifact content, approval status, delivery metadataAiEmployeeMemoryType— memory key-value pairsApprovalRateDataType— weekly approval/rejection/auto-rejection countsPromotionCriteriaType— approval rate, weeks active, recent rejections, promotability
Integration Endpoints
Service-to-service endpoints authenticated via HMAC-SHA256 over the request body, using the shared secret in the RAILS_WEBHOOK_SECRET env var. The signature is sent as the X-Workforce-Signature header. Same pattern as /webhooks/ai-workforce (see agent-runner.md).
POST /integrations/feedback/export
Returns FeedbackPost rows for an external poller (the Multica Riley — Objectuve feedback ingest autopilot — see docs/guides/multica-autopilots.md). Read-only; no DB writes.
Auth: X-Workforce-Signature: <hex> where <hex> = HMAC-SHA256(RAILS_WEBHOOK_SECRET, body).
Request body (all fields optional):
{
"since": "2026-05-08T12:00:00Z",
"limit": 100
}since— ISO8601 timestamp; only returns posts withcreated_at > since. Omit for the first run.limit— integer, default100, clamped to[1, 500].
Response:
{
"feedback_posts": [
{
"public_id": "abc123",
"title": "Add weekly digest email",
"description": "...",
"category": "feature",
"status": "open",
"vote_count": 7,
"comment_count": 2,
"author_username": "jane_doe",
"author_public_id": "user-xyz",
"created_at": "2026-05-08T11:32:14Z",
"admin_url": "https://admin.objectuve.com/feedback?post=abc123"
}
],
"next_since": "2026-05-08T11:32:14.871234Z"
}next_since is emitted at microsecond precision when posts are returned (so cursors round-trip exactly across runs); when no posts match, the controller echoes the since value the caller sent verbatim.
category ∈ feature | improvement | bug | other. status ∈ open | planned | in_progress | completed | declined.
Soft-deleted posts (deleted_at IS NOT NULL) are excluded automatically.
Status codes:
| Code | Meaning |
|---|---|
200 | Posts (possibly empty array) |
400 | Malformed JSON body |
401 | Missing/invalid signature, or RAILS_WEBHOOK_SECRET unset |
POST /integrations/activation-funnel
Returns week-over-week activation funnel metrics for an external poller (the Multica OBJ-450 autopilot — see OBJ-450). Compares current 7-day window to previous 7-day window. Read-only; no DB writes.
Auth: X-Workforce-Signature: <hex> where <hex> = HMAC-SHA256(RAILS_WEBHOOK_SECRET, body).
Request body (empty, required):
{}The endpoint accepts an empty JSON object. The request body is required for HMAC signature calculation.
Response:
{
"as_of": "2026-05-20T12:00:00Z",
"window_days": 7,
"current": {
"signed_in": 245,
"wizard_completed": 189,
"first_goal": 156,
"first_check_in": 124,
"first_badge": 98
},
"previous": {
"signed_in": 220,
"wizard_completed": 168,
"first_goal": 142,
"first_check_in": 112,
"first_badge": 89
},
"wow_pct": {
"signed_in": 11.4,
"wizard_completed": 12.5,
"first_goal": 9.9,
"first_check_in": 10.7,
"first_badge": 10.1
},
"skip_run": false
}as_of— ISO8601 timestamp when the metrics were computed (UTC)window_days— Length of the 7-day windowcurrent— Activation funnel step counts for the current 7-day window (ending atas_of)previous— Activation funnel step counts for the previous 7-day window (7–14 days beforeas_of)wow_pct— Week-over-week percentage change per step. Computed as((current - previous) / previous * 100).round(1). Whenprevious == 0, the value isnil(no baseline to compare against)skip_run—trueif the current window has zero sign-ins (no new users to measure);falseotherwise. Signals to the autopilot whether metrics are meaningful
Status codes:
| Code | Meaning |
|---|---|
200 | Metrics (with all 5 funnel steps) |
400 | Malformed JSON body |
401 | Missing/invalid signature, or RAILS_WEBHOOK_SECRET unset |
422 | Interaction failed (query error or unexpected state) |
Schema Files
| File | Description |
|---|---|
rails_api/schema.graphql | Full GraphQL SDL schema (auto-generated from Ruby types) |
rails_api/spectaql-config.yml | Spectaql documentation config |
rails_api/spectaql/metadata.json | Field descriptions and request/response examples |
rails_api/generate-voyager.js | Script to build the Voyager schema explorer |
Last updated: 2026-09-14 — added the aiRequestUpdate subscription and aiRequest query (v4.60 Phase 1, OBJ-3758)