Skip to content

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):

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

ProtocolURLPurpose
POST/graphqlAll queries, mutations, and batch operations
WS/cableReal-time subscriptions (ActionCable)
GET/healthDetailed health check (DB, Redis, Sidekiq) — returns 200 or 503
GET/upSimple 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:

graphql
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:

json
[
  { "query": "query { goalCategories { id name } }" },
  { "query": "query { goalKinds { id name } }" }
]

Real-time Subscriptions (WebSocket)

Connect to WS /cable using ActionCable. Two subscriptions are available:

graphql
subscription {
  notificationUpdate(userId: "abc123XYZ") {
    id
    kind
    content
    acknowledged
  }
}
graphql
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

ToolURL (local dev)Description
Spectaqlhttp://localhost:3000/docs/Interactive API reference with examples, argument docs, and type explorer
Voyagerhttp://localhost:3000/docs/voyager.htmlVisual schema graph — explore type relationships interactively

Regenerating Documentation

Documentation is generated from schema.graphql which is dumped from the Rails GraphQL gem.

bash
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.html

Run npm install if dependencies are not yet installed.


Key Operations Quick Reference

Authentication

OperationTypeDescription
syncUserMutationFind-or-create the local user from the Clerk JWT and return firstSignIn for onboarding routing
authzCheckQueryCheck whether the current user holds a permission (e.g. admin)

Goals

OperationTypeDescription
goalsQueryList the current user's top-level goals
goalQueryFetch a single goal by ID
publicGoalQueryFetch a public goal (no auth required)
addGoalMutationCreate a new goal
updateGoalMutationUpdate an existing goal
addGoalEventMutationLog a progress event
generateMilestonesMutationAI-generate sub-goal milestones

Communities

OperationTypeDescription
communitiesQueryList all or filtered communities
communityFeedQueryPaginated post feed for a community
createCommunityMutationCreate a new community
joinCommunityMutationJoin a community
createCommunityPostMutationPost an update to a community

Habits & Progress

OperationTypeDescription
checkInHabitMutationOne-tap habit check-in for today
useStreakFreezeMutationUse a freeze to preserve a habit streak
goalProgressDataQueryProgress chart data (events grouped by day/week/month, pace, streaks)
unifiedFeedQueryPaginated unified feed of ally, community, and own activity

Accountability Partners

OperationTypeDescription
accountabilityPartnerQueryFetch the current user's active accountability partner (or null)
sendPartnerRequestMutationSend an accountability partner request to an accepted ally
acceptPartnerRequestMutationAccept a pending partner request
declinePartnerRequestMutationDecline a pending partner request (no notification sent)
endPartnershipMutationEnd an active accountability partnership

Community Challenges

OperationTypeDescription
createCommunityChallengeMutationCreate a time-boxed challenge for a community
joinCommunityChallengeMutationJoin an active or upcoming challenge as a participant
leaveCommunityChallengeMutationLeave a challenge (refunds participation, clears progress)
communityChallengeLeaderboardQueryFetch leaderboard rankings for a challenge (paginated)

Mood & Insights

OperationTypeDescription
addMoodLogMutationRecord a mood check-in
getInsightMutationAI insights on progress patterns
getAdviceMutationAI advice for a specific goal

Async AI Delivery (v4.60 Phase 1)

OperationTypeDescription
aiRequestQueryFetch a single async AiRequest by id — the reconnect-recovery counterpart to aiRequestUpdate
aiRequestUpdateSubscriptionStream 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)

OperationTypeDescription
myTeam / teamHome / teamSettingsQueryThe authenticated user's team, the TeamHomeView aggregate read, and the TeamSettingsView aggregate read
teamInvitePreviewQueryPublic, unauthenticated preview of an invite for /join-team/{code}
createTeamInvite / revokeTeamInvite / acceptTeamInviteMutationCreate, revoke, or accept a team invite
promoteTeamMember / removeTeamMemberMutationChange a member's role, or remove them from the team
createSubCommunity / archiveSubCommunity / unarchiveSubCommunity / setDefaultSubCommunityMutationCreate or manage a team's sub-communities (rooms)
joinSubCommunity / leaveSubCommunityMutationSelf-service join/leave for an open sub-community
teamLeaderboardQueryRanked, opted-in leaderboard entries for a team or sub-community, scoped by weekly/monthly/all-time period
setLeaderboardVisibilityMutationSelf-service member opt-out/opt-in from the team leaderboard
teamLeaderboardOptOutStatsQueryAdmin-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

QueryArgumentsReturnsDescription
aiEmployees[AiEmployeeType]All employees with runs preloaded
pendingArtifacts[AiArtifactType]Pending artifacts sorted by creation time
aiEmployeeid: String!AiEmployeeTypeEmployee detail with memories, runs, approval rate, promotion criteria
aiRunid: String!AiRunTypeRun detail with artifacts and execution log

Mutations

MutationArgumentsReturnsDescription
triggerAiRunemployeeId: String!{ run, errors }Manually trigger an employee run
pauseAiEmployeeemployeeId: String!, active: Boolean!{ employee, errors }Pause or resume an employee
updateAiEmployeeemployeeId: String!, name?, description?, taskPrompt?, monthlyBudgetCents?, modelPreference?, scheduleCron?, autonomyLevel?, confirmPromotion?{ employee, errors }Update employee config or promote/demote autonomy
approveAiArtifactartifactId: String!, editedPayload?: String{ artifact, errors }Approve artifact (triggers delivery)
rejectAiArtifactartifactId: String!, rejectionReason: String!{ artifact, errors }Reject artifact with reason (min 10 chars)

Webhook Endpoint

MethodPathAuthDescription
POST/webhooks/ai-workforceHMAC-SHA256 (X-Workforce-Signature)Agent Runner posts run results

AI Workforce Types

  • AiEmployeeType — employee config, budget, schedule, promotion criteria, memories, runs
  • AiRunType — run status, tokens, cost, execution log, artifacts
  • AiArtifactType — artifact content, approval status, delivery metadata
  • AiEmployeeMemoryType — memory key-value pairs
  • ApprovalRateDataType — weekly approval/rejection/auto-rejection counts
  • PromotionCriteriaType — 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):

json
{
  "since": "2026-05-08T12:00:00Z",
  "limit": 100
}
  • since — ISO8601 timestamp; only returns posts with created_at > since. Omit for the first run.
  • limit — integer, default 100, clamped to [1, 500].

Response:

json
{
  "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.

categoryfeature | improvement | bug | other. statusopen | planned | in_progress | completed | declined.

Soft-deleted posts (deleted_at IS NOT NULL) are excluded automatically.

Status codes:

CodeMeaning
200Posts (possibly empty array)
400Malformed JSON body
401Missing/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):

json
{}

The endpoint accepts an empty JSON object. The request body is required for HMAC signature calculation.

Response:

json
{
  "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 window
  • current — Activation funnel step counts for the current 7-day window (ending at as_of)
  • previous — Activation funnel step counts for the previous 7-day window (7–14 days before as_of)
  • wow_pct — Week-over-week percentage change per step. Computed as ((current - previous) / previous * 100).round(1). When previous == 0, the value is nil (no baseline to compare against)
  • skip_runtrue if the current window has zero sign-ins (no new users to measure); false otherwise. Signals to the autopilot whether metrics are meaningful

Status codes:

CodeMeaning
200Metrics (with all 5 funnel steps)
400Malformed JSON body
401Missing/invalid signature, or RAILS_WEBHOOK_SECRET unset
422Interaction failed (query error or unexpected state)

Schema Files

FileDescription
rails_api/schema.graphqlFull GraphQL SDL schema (auto-generated from Ruby types)
rails_api/spectaql-config.ymlSpectaql documentation config
rails_api/spectaql/metadata.jsonField descriptions and request/response examples
rails_api/generate-voyager.jsScript to build the Voyager schema explorer

Last updated: 2026-09-14 — added the aiRequestUpdate subscription and aiRequest query (v4.60 Phase 1, OBJ-3758)

Loading…