{"components":{"responses":{"400":{"content":{"application/problem+json":{"example":{"code":"bad_request","detail":"missing model","requestId":"req-abc123","status":400,"title":"Bad Request","type":"https://api.rowboat.dev/problems/bad_request"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad request. The request is malformed, missing a required parameter, or has invalid JSON."},"401":{"content":{"application/problem+json":{"example":{"code":"unauthorized","detail":"missing bearer token","requestId":"req-abc123","status":401,"title":"Unauthorized","type":"https://api.rowboat.dev/problems/unauthorized"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Unauthorized. Missing, invalid, or expired bearer token or shared secret."},"402":{"content":{"application/problem+json":{"example":{"code":"insufficient_credits","detail":"insufficient_credits","requestId":"req-abc123","status":402,"title":"Payment Required","type":"https://api.rowboat.dev/problems/insufficient_credits"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payment required. The user does not have enough credits for the requested metered call."},"403":{"content":{"application/problem+json":{"example":{"code":"forbidden","detail":"ticket does not belong to this user","requestId":"req-abc123","status":403,"title":"Forbidden","type":"https://api.rowboat.dev/problems/forbidden"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Forbidden. The caller is authenticated but cannot access this resource."},"404":{"content":{"application/problem+json":{"example":{"code":"not_connected","detail":"connector not connected","requestId":"req-abc123","status":404,"title":"Not Found","type":"https://api.rowboat.dev/problems/not_connected"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Not found. The requested resource, connector, or OAuth handoff ticket does not exist."},"409":{"content":{"application/problem+json":{"example":{"code":"reconnect_required","detail":"Google reports invalid_grant; user must reconnect.","reconnectRequired":true,"requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/reconnect_required"},"schema":{"$ref":"#/components/schemas/ReconnectErrorEnvelope"}}},"description":"Conflict. Usually means an upstream refresh token is invalid and the user must reconnect."},"410":{"content":{"application/problem+json":{"example":{"code":"ticket_expired","detail":"ticket expired","requestId":"req-abc123","status":410,"title":"Gone","type":"https://api.rowboat.dev/problems/ticket_expired"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Gone. A one-time handoff ticket existed but expired before redemption."},"429":{"content":{"application/problem+json":{"example":{"code":"rate_limited","detail":"rate limit exceeded","requestId":"req-abc123","status":429,"title":"Too Many Requests","type":"https://api.rowboat.dev/problems/rate_limited"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Too many requests. A per-user rate limit bucket rejected the request."},"500":{"content":{"application/problem+json":{"example":{"code":"internal_error","detail":"could not load billing","requestId":"req-abc123","status":500,"title":"Internal Server Error","type":"https://api.rowboat.dev/problems/internal_error"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Internal server error."},"502":{"content":{"application/problem+json":{"example":{"code":"provider_unconfigured","detail":"provider not configured","requestId":"req-abc123","status":502,"title":"Bad Gateway","type":"https://api.rowboat.dev/problems/provider_unconfigured"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Bad gateway. A configured upstream provider failed or the provider is not configured."},"503":{"content":{"application/problem+json":{"example":{"code":"auth_unavailable","detail":"authentication unavailable","requestId":"req-abc123","status":503,"title":"Service Unavailable","type":"https://api.rowboat.dev/problems/auth_unavailable"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Service unavailable. Authentication or readiness dependencies are temporarily unavailable."}},"schemas":{"ActionOutcome":{"properties":{"action":{"$ref":"#/components/schemas/RevenueAction"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"kind":{"type":"string"},"metadata_json":{"type":"string"},"occurred_at":{"format":"date-time","type":"string"},"source":{"type":"string"},"source_event_id":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","kind","source","source_event_id","occurred_at","workspace","action","user"],"type":"object"},"ActionProposal":{"properties":{"approved_at":{"format":"date-time","type":"string"},"correlation_id":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"entity_id":{"type":"string"},"executed_at":{"format":"date-time","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"date-time","type":"string"},"financial":{"type":"boolean"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"kind":{"type":"string"},"origin_run_id":{"type":"string"},"params_json":{"type":"string"},"rationale":{"type":"string"},"reason":{"description":"Reason code for the ledger entry.","enum":["llm_call","llm_call_reserve","llm_settle","voice_tts","exa_search","grant","refund"],"example":"llm_settle","type":"string"},"resolved_at":{"format":"date-time","type":"string"},"result_ref":{"type":"string"},"return_event_id":{"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"target":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","target","kind","financial","status","user"],"type":"object"},"AgentApproval":{"properties":{"approval_id":{"type":"string"},"approval_token_ref":{"type":"string"},"args_redacted_json":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"requested_at":{"format":"date-time","type":"string"},"requested_by":{"type":"string"},"resolved_at":{"format":"date-time","type":"string"},"resolved_by":{"type":"string"},"session":{"$ref":"#/components/schemas/AgentSession"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"tool_call_index":{"type":"integer"},"tool_name":{"type":"string"},"trust_tier":{"type":"string"},"turn_seq":{"type":"integer"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","approval_id","turn_seq","tool_call_index","tool_name","status","requested_at","user","session"],"type":"object"},"AgentDefinition":{"properties":{"agent_sync_error":{"type":"string"},"agent_sync_state":{"type":"string"},"channel_bindings":{"type":"string"},"connector_reqs":{"items":{"type":"string"},"type":"array"},"content_hash":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"enabled_tools":{"items":{"type":"string"},"type":"array"},"forked_from":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"instructions":{"type":"string"},"limits_json":{"type":"string"},"managed_by":{"type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","type":"string"},"name":{"type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","type":"string"},"raw_source":{"type":"string"},"revision":{"type":"integer"},"sessions":{"items":{"$ref":"#/components/schemas/AgentSession"},"type":"array"},"slug":{"type":"string"},"source":{"type":"string"},"source_format":{"type":"string"},"subagent_refs":{"items":{"type":"string"},"type":"array"},"tools_json":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","slug","name","source","revision","source_format","managed_by","agent_sync_state","user"],"type":"object"},"AgentDefinitionHistory":{"properties":{"agent_sync_error":{"type":"string"},"agent_sync_state":{"type":"string"},"channel_bindings":{"type":"string"},"connector_reqs":{"items":{"type":"string"},"type":"array"},"content_hash":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"enabled_tools":{"items":{"type":"string"},"type":"array"},"forked_from":{"type":"string"},"history_time":{"description":"Timestamp when this history record was written.","example":"2026-06-04T20:40:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"instructions":{"type":"string"},"limits_json":{"type":"string"},"managed_by":{"type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","type":"string"},"name":{"type":"string"},"operation":{"description":"Mutation operation that produced this history row.","enum":["INSERT","UPDATE","DELETE"],"example":"UPDATE","type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","type":"string"},"raw_source":{"type":"string"},"ref":{"description":"UUID of the source row represented by a history row.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"revision":{"type":"integer"},"slug":{"type":"string"},"source":{"type":"string"},"source_format":{"type":"string"},"subagent_refs":{"items":{"type":"string"},"type":"array"},"tools_json":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"}},"required":["id","created_at","updated_at","history_time","operation","slug","name","source","revision","source_format","managed_by","agent_sync_state"],"type":"object"},"AgentSession":{"properties":{"agent":{"$ref":"#/components/schemas/AgentDefinition"},"agent_revision":{"type":"integer"},"agent_slug":{"type":"string"},"agent_source":{"type":"string"},"approvals":{"items":{"$ref":"#/components/schemas/AgentApproval"},"type":"array"},"channel":{"type":"string"},"channel_key":{"type":"string"},"completed_at":{"format":"date-time","type":"string"},"cost_units":{"description":"Settled credit cost for the request.","example":8,"type":"integer"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"error":{"type":"string"},"error_code":{"type":"string"},"events":{"items":{"$ref":"#/components/schemas/AgentSessionEvent"},"type":"array"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"last_activity_at":{"format":"date-time","type":"string"},"llm_call_count":{"type":"integer"},"revision":{"type":"integer"},"session_id":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"temporal_run_id":{"type":"string"},"temporal_workflow_id":{"type":"string"},"title":{"type":"string"},"tool_call_count":{"type":"integer"},"turn_count":{"type":"integer"},"turns":{"items":{"$ref":"#/components/schemas/AgentTurn"},"type":"array"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","session_id","agent_slug","agent_revision","status","channel","turn_count","llm_call_count","tool_call_count","cost_units","revision","user"],"type":"object"},"AgentSessionEvent":{"properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"event_json":{"type":"string"},"event_type":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"received_at":{"format":"date-time","type":"string"},"seq":{"type":"integer"},"session":{"$ref":"#/components/schemas/AgentSession"},"turn_seq":{"type":"integer"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","seq","event_json","received_at","user","session"],"type":"object"},"AgentToolCall":{"properties":{"args_json":{"type":"string"},"call_index":{"type":"integer"},"completed_at":{"format":"date-time","type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"error_code":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"result_bytes":{"type":"integer"},"started_at":{"format":"date-time","type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"tool_name":{"type":"string"},"trust_tier":{"type":"string"},"turn":{"$ref":"#/components/schemas/AgentTurn"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","call_index","tool_name","result_bytes","status","user","turn"],"type":"object"},"AgentToolResultBlob":{"properties":{"call_index":{"type":"integer"},"content":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"session_id":{"type":"string"},"tool_name":{"type":"string"},"total_bytes":{"type":"integer"},"turn_seq":{"type":"integer"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","session_id","turn_seq","call_index","content","total_bytes","user"],"type":"object"},"AgentTurn":{"properties":{"completed_at":{"format":"date-time","type":"string"},"cost_units":{"description":"Settled credit cost for the request.","example":8,"type":"integer"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"finish_reason":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"input":{"type":"string"},"llm_call_count":{"type":"integer"},"seq":{"type":"integer"},"session":{"$ref":"#/components/schemas/AgentSession"},"started_at":{"format":"date-time","type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"summary":{"type":"string"},"tool_call_count":{"type":"integer"},"tool_calls":{"items":{"$ref":"#/components/schemas/AgentToolCall"},"type":"array"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","seq","status","llm_call_count","tool_call_count","cost_units","user","session"],"type":"object"},"ApprovalToken":{"properties":{"consumed":{"type":"boolean"},"consumed_at":{"format":"date-time","type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"operator_user_id":{"type":"string"},"params_hash":{"type":"string"},"proposal_id":{"type":"string"},"step_up":{"type":"boolean"},"token_hash":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","token_hash","proposal_id","params_hash","operator_user_id","step_up","expires_at","consumed","user"],"type":"object"},"BackgroundTask":{"description":"Server-readable mirror of one desktop background task spec. Owned by a user and keyed by slug per user.","properties":{"active":{"description":"Whether the background task is active for scheduling and remote trigger pickup.","example":true,"type":"boolean"},"createdAt":{"description":"Original desktop task creation timestamp when known; otherwise the server row creation time.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"executionTarget":{"description":"Where this task executes. desktop preserves the local-first path; api dispatches to the Temporal-backed API worker.","enum":["desktop","api"],"example":"desktop","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"instructions":{"description":"Background task instructions mirrored from task.yaml.","example":"Summarize important account changes.","type":"string"},"lastAttemptAt":{"description":"Last time the desktop attempted to run this task.","example":"2026-06-04T21:00:00Z","format":"date-time","nullable":true,"type":"string"},"lastRunAt":{"description":"Last time the desktop completed or recorded a run for this task.","example":"2026-06-04T21:02:00Z","format":"date-time","nullable":true,"type":"string"},"lastRunError":{"description":"Latest run error, empty when the latest run did not fail.","example":"","nullable":true,"type":"string"},"lastRunId":{"description":"Last desktop or remote-trigger run id mirrored for this task.","example":"run-20260604-210000","nullable":true,"type":"string"},"lastRunSummary":{"description":"Short summary from the latest run.","example":"No high-priority account changes.","nullable":true,"type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","nullable":true,"type":"string"},"name":{"description":"Human-readable background task name.","example":"Daily Account Summary","type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","nullable":true,"type":"string"},"revision":{"description":"Optimistic-lock revision used by write endpoints.","example":2,"type":"integer"},"slug":{"description":"Stable per-user background task slug matching bg-tasks/<slug> locally.","example":"daily-summary","type":"string"},"triggers":{"description":"Task trigger configuration mirrored from the desktop task.yaml. Common shapes include cron schedules, window schedules, or event subscriptions. Null clears the mirrored trigger config on PATCH.","example":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"nullable":true},"updatedAt":{"description":"Server timestamp for the last mirrored task update.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"}},"required":["id","slug","name","instructions","active","executionTarget","createdAt","updatedAt","revision"],"type":"object"},"BackgroundTaskArtifact":{"description":"Markdown artifact mirror for bg-tasks/<slug>/index.md.","properties":{"body":{"description":"Markdown artifact body for a background task.","example":"# Daily Account Summary\n\nContext.","type":"string"},"revision":{"description":"Optimistic-lock revision used by write endpoints.","example":2,"type":"integer"},"slug":{"description":"Stable per-user background task slug matching bg-tasks/<slug> locally.","example":"daily-summary","type":"string"},"updatedAt":{"description":"Server timestamp for the last artifact update.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"}},"required":["slug","body","revision","updatedAt"],"type":"object"},"BackgroundTaskArtifactPutRequest":{"description":"Creates or revision-checks an artifact mirror update. Omit revision or send 0 when creating a missing artifact.","properties":{"body":{"description":"Full markdown body to store.","example":"# Daily Account Summary\n\nUpdated context.","type":"string"},"revision":{"description":"Current artifact revision. Required for updates to an existing artifact.","example":2,"type":"integer"}},"required":["body"],"type":"object"},"BackgroundTaskCreateRequest":{"description":"Creates or first-syncs a desktop background task into the cloud mirror.","properties":{"active":{"description":"Whether this task is active. Defaults to true.","example":true,"type":"boolean"},"createdAt":{"description":"Original desktop task creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","nullable":true,"type":"string"},"executionTarget":{"description":"Where this task should execute. Defaults to desktop.","enum":["desktop","api"],"example":"desktop","type":"string"},"instructions":{"description":"Task instructions mirrored from task.yaml.","example":"Summarize important account changes and draft follow-up notes.","type":"string"},"lastAttemptAt":{"description":"Last attempt timestamp from local state.","example":"2026-06-04T21:00:00Z","format":"date-time","nullable":true,"type":"string"},"lastRunAt":{"description":"Last local run timestamp.","example":"2026-06-04T21:02:00Z","format":"date-time","nullable":true,"type":"string"},"lastRunError":{"description":"Latest local run error.","example":"","nullable":true,"type":"string"},"lastRunId":{"description":"Last local run id from the desktop.","example":"run-20260604-210000","nullable":true,"type":"string"},"lastRunSummary":{"description":"Latest local run summary.","example":"No high-priority account changes.","nullable":true,"type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","nullable":true,"type":"string"},"name":{"description":"Human-readable task name.","example":"Daily Account Summary","type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","nullable":true,"type":"string"},"slug":{"description":"Optional stable slug. If omitted, rowboat-api slugifies name.","example":"daily-summary","nullable":true,"type":"string"},"triggers":{"description":"Task trigger configuration mirrored from the desktop task.yaml. Common shapes include cron schedules, window schedules, or event subscriptions. Null clears the mirrored trigger config on PATCH.","example":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"nullable":true}},"required":["name","instructions"],"type":"object"},"BackgroundTaskListResponse":{"description":"Task list for the authenticated user, ordered by slug.","properties":{"tasks":{"description":"Mirrored background tasks visible to this user.","items":{"$ref":"#/components/schemas/BackgroundTask"},"type":"array"}},"required":["tasks"],"type":"object"},"BackgroundTaskPatchRequest":{"description":"Revision-checked partial update for the task mirror. Omitted fields are left unchanged; triggers:null clears the trigger JSON.","properties":{"active":{"description":"Enable or disable local scheduling/remote pickup.","example":true,"type":"boolean"},"createdAt":{"description":"Original desktop task creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","nullable":true,"type":"string"},"executionTarget":{"description":"Where this task should execute.","enum":["desktop","api"],"example":"api","type":"string"},"instructions":{"description":"New task instructions.","example":"Summarize important account changes and draft follow-up notes.","nullable":true,"type":"string"},"lastAttemptAt":{"description":"Latest local attempt timestamp.","example":"2026-06-04T21:00:00Z","format":"date-time","nullable":true,"type":"string"},"lastRunAt":{"description":"Latest local run timestamp.","example":"2026-06-04T21:02:00Z","format":"date-time","nullable":true,"type":"string"},"lastRunError":{"description":"Latest local run error.","example":"","nullable":true,"type":"string"},"lastRunId":{"description":"Latest local run id.","example":"run-20260604-210000","nullable":true,"type":"string"},"lastRunSummary":{"description":"Latest local run summary.","example":"No high-priority account changes.","nullable":true,"type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","nullable":true,"type":"string"},"name":{"description":"New task name.","example":"Daily Account Summary","nullable":true,"type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","nullable":true,"type":"string"},"revision":{"description":"Current task revision returned by the last GET/list/PATCH response.","example":2,"type":"integer"},"triggers":{"description":"Task trigger configuration mirrored from the desktop task.yaml. Common shapes include cron schedules, window schedules, or event subscriptions. Null clears the mirrored trigger config on PATCH.","example":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"nullable":true}},"required":["revision"],"type":"object"},"BackgroundTaskRun":{"description":"Mirrored run state for one desktop background task execution or queued remote trigger.","properties":{"completedAt":{"description":"Desktop run completion timestamp.","example":"2026-06-04T21:02:00Z","format":"date-time","nullable":true,"type":"string"},"createdAt":{"description":"Server row creation timestamp.","example":"2026-06-04T21:00:30Z","format":"date-time","type":"string"},"error":{"description":"Run error mirrored from the desktop.","example":"","nullable":true,"type":"string"},"executor":{"description":"Execution backend that owns this run.","enum":["desktop","api"],"example":"api","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"lastHeartbeatAt":{"description":"Latest worker heartbeat/progress timestamp.","example":"2026-06-04T21:01:30Z","format":"date-time","nullable":true,"type":"string"},"localRunId":{"description":"Actual desktop run id once a queued remote trigger has been claimed and executed locally.","example":"local-run-42","nullable":true,"type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","nullable":true,"type":"string"},"previousRunId":{"description":"Previous run id when this run was created by retry.","example":"run-20260604-210000","nullable":true,"type":"string"},"progressMessage":{"description":"Human-readable progress message for polling clients.","example":"Building API-native task artifact.","nullable":true,"type":"string"},"progressPercent":{"description":"Best-known run progress for polling clients, 0-100.","example":50,"nullable":true,"type":"integer"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","nullable":true,"type":"string"},"requestedContext":{"description":"Optional context supplied when a user remotely triggered the task.","example":"Run this now and focus on high-risk accounts.","nullable":true,"type":"string"},"revision":{"description":"Optimistic-lock revision used by write endpoints.","example":2,"type":"integer"},"runId":{"description":"Cloud-visible run id. Desktop-created runs can use local ids; remote triggers use remote-trigger-<uuid> until claimed.","example":"run-20260604-210000","type":"string"},"slug":{"description":"Stable per-user background task slug matching bg-tasks/<slug> locally.","example":"daily-summary","type":"string"},"startedAt":{"description":"Desktop run start timestamp.","example":"2026-06-04T21:01:00Z","format":"date-time","nullable":true,"type":"string"},"status":{"description":"Background task run lifecycle state.","enum":["queued","running","succeeded","failed","stopped"],"example":"succeeded","type":"string"},"subUseCase":{"description":"Task-specific usage label for cost attribution.","example":"daily-summary","nullable":true,"type":"string"},"summary":{"description":"Run summary mirrored from the desktop.","example":"No high-priority account changes.","nullable":true,"type":"string"},"temporalClosedAt":{"description":"Timestamp when Temporal execution closed.","example":"2026-06-04T21:02:00Z","format":"date-time","nullable":true,"type":"string"},"temporalRunId":{"description":"Temporal run id for the current workflow execution.","example":"00000000-0000-0000-0000-000000000001","nullable":true,"type":"string"},"temporalStartedAt":{"description":"Timestamp when Temporal execution started.","example":"2026-06-04T21:01:00Z","format":"date-time","nullable":true,"type":"string"},"temporalStatus":{"description":"Last mirrored Temporal status, separate from the product status.","example":"Running","nullable":true,"type":"string"},"temporalWorkflowId":{"description":"Temporal workflow id for API-worker runs.","example":"background-task/user/daily-summary/api-trigger-123","nullable":true,"type":"string"},"trigger":{"description":"Trigger source for a task run.","enum":["manual","cron","window","event"],"example":"manual","type":"string"},"updatedAt":{"description":"Server row update timestamp.","example":"2026-06-04T21:02:05Z","format":"date-time","type":"string"},"useCase":{"description":"High-level usage label for cost attribution.","example":"background-task","nullable":true,"type":"string"}},"required":["id","runId","slug","trigger","status","executor","createdAt","updatedAt","revision"],"type":"object"},"BackgroundTaskRunCreateRequest":{"description":"Creates a run mirror for a desktop execution. Remote/manual queue creation usually uses POST /trigger instead.","properties":{"completedAt":{"description":"Run completion timestamp.","example":"2026-06-04T21:02:00Z","format":"date-time","nullable":true,"type":"string"},"error":{"description":"Initial run error.","example":"","nullable":true,"type":"string"},"executor":{"description":"Execution backend. Defaults from task.executionTarget.","enum":["desktop","api"],"example":"desktop","type":"string"},"lastHeartbeatAt":{"description":"Latest heartbeat timestamp.","example":"2026-06-04T21:01:30Z","format":"date-time","nullable":true,"type":"string"},"localRunId":{"description":"Desktop-local run id if different from runId.","example":"local-run-42","nullable":true,"type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","nullable":true,"type":"string"},"previousRunId":{"description":"Previous run id when this is a retry.","example":"run-20260604-205000","nullable":true,"type":"string"},"progressMessage":{"description":"Initial progress message.","example":"Queued for API worker.","nullable":true,"type":"string"},"progressPercent":{"description":"Initial progress for polling clients.","example":0,"nullable":true,"type":"integer"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","nullable":true,"type":"string"},"requestedContext":{"description":"Remote trigger context if this run was queued by the API.","example":"Run this now.","nullable":true,"type":"string"},"runId":{"description":"Cloud-visible run id from the desktop.","example":"run-20260604-210000","type":"string"},"startedAt":{"description":"Run start timestamp.","example":"2026-06-04T21:01:00Z","format":"date-time","nullable":true,"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["queued","running","succeeded","failed","stopped"],"example":"active","type":"string"},"subUseCase":{"description":"Task-specific usage label.","example":"daily-summary","nullable":true,"type":"string"},"summary":{"description":"Initial run summary.","example":"started","nullable":true,"type":"string"},"temporalRunId":{"description":"Temporal run id.","example":"00000000-0000-0000-0000-000000000001","nullable":true,"type":"string"},"temporalStatus":{"description":"Last mirrored Temporal status.","example":"Started","nullable":true,"type":"string"},"temporalWorkflowId":{"description":"Temporal workflow id for API-worker runs.","example":"background-task/user/daily-summary/api-trigger-123","nullable":true,"type":"string"},"trigger":{"description":"Trigger source. Defaults to manual.","enum":["manual","cron","window","event"],"example":"manual","type":"string"},"useCase":{"description":"High-level usage label.","example":"background-task","nullable":true,"type":"string"}},"required":["runId"],"type":"object"},"BackgroundTaskRunEvent":{"description":"Mirrored JSONL event from a background task run log.","properties":{"event":{"additionalProperties":true,"description":"Original JSON event object from the desktop run log.","type":"object"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"receivedAt":{"description":"Server timestamp when the event was stored.","example":"2026-06-04T21:02:05Z","format":"date-time","type":"string"},"seq":{"description":"Zero-based sequence number for a mirrored JSONL run event.","example":1,"type":"integer"},"type":{"description":"Event type, either supplied explicitly or copied from event.type.","example":"temporal.completed","nullable":true,"type":"string"}},"required":["id","seq","event","receivedAt"],"type":"object"},"BackgroundTaskRunEventInput":{"description":"One event to append to a run log mirror.","properties":{"event":{"additionalProperties":true,"description":"Original JSON event object from the desktop run log.","type":"object"},"seq":{"description":"Zero-based sequence number within the run log.","example":1,"type":"integer"},"type":{"description":"Optional event type. If omitted, rowboat-api reads event.type when present.","example":"temporal.completed","nullable":true,"type":"string"}},"required":["seq","event"],"type":"object"},"BackgroundTaskRunEventsAppendRequest":{"description":"Batch append for JSONL run events. Existing seq values are skipped to make retries idempotent.","properties":{"events":{"description":"Events to append.","items":{"$ref":"#/components/schemas/BackgroundTaskRunEventInput"},"type":"array"}},"required":["events"],"type":"object"},"BackgroundTaskRunEventsAppendResponse":{"description":"Append result counts.","properties":{"skipped":{"description":"Number of duplicate seq events ignored.","example":1,"type":"integer"},"stored":{"description":"Number of events inserted.","example":2,"type":"integer"}},"required":["stored","skipped"],"type":"object"},"BackgroundTaskRunEventsResponse":{"description":"Ordered durable task log/progress event list for a run.","properties":{"events":{"description":"Run log/progress events ordered by seq.","items":{"$ref":"#/components/schemas/BackgroundTaskRunEvent"},"type":"array"}},"required":["events"],"type":"object"},"BackgroundTaskRunPatchRequest":{"description":"Revision-checked update for mirrored run state.","properties":{"completedAt":{"description":"Run completion timestamp.","example":"2026-06-04T21:02:00Z","format":"date-time","nullable":true,"type":"string"},"error":{"description":"Latest run error.","example":"","nullable":true,"type":"string"},"executor":{"description":"Execution backend.","enum":["desktop","api"],"example":"api","type":"string"},"lastHeartbeatAt":{"description":"Latest heartbeat timestamp.","example":"2026-06-04T21:01:30Z","format":"date-time","nullable":true,"type":"string"},"localRunId":{"description":"Desktop-local run id after a queued trigger is claimed.","example":"local-run-42","nullable":true,"type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","nullable":true,"type":"string"},"previousRunId":{"description":"Previous run id when this is a retry.","example":"run-20260604-205000","nullable":true,"type":"string"},"progressMessage":{"description":"Progress message.","example":"Building API-native task artifact.","nullable":true,"type":"string"},"progressPercent":{"description":"Progress for polling clients, 0-100.","example":50,"nullable":true,"type":"integer"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","nullable":true,"type":"string"},"requestedContext":{"description":"Remote trigger context.","example":"Run this now.","nullable":true,"type":"string"},"revision":{"description":"Current run revision.","example":1,"type":"integer"},"startedAt":{"description":"Run start timestamp.","example":"2026-06-04T21:01:00Z","format":"date-time","nullable":true,"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["queued","running","succeeded","failed","stopped"],"example":"active","type":"string"},"subUseCase":{"description":"Task-specific usage label.","example":"daily-summary","nullable":true,"type":"string"},"summary":{"description":"Latest run summary.","example":"No high-priority account changes.","nullable":true,"type":"string"},"temporalClosedAt":{"description":"Temporal close timestamp.","example":"2026-06-04T21:02:00Z","format":"date-time","nullable":true,"type":"string"},"temporalRunId":{"description":"Temporal run id.","example":"00000000-0000-0000-0000-000000000001","nullable":true,"type":"string"},"temporalStartedAt":{"description":"Temporal start timestamp.","example":"2026-06-04T21:01:00Z","format":"date-time","nullable":true,"type":"string"},"temporalStatus":{"description":"Last mirrored Temporal status.","example":"Running","nullable":true,"type":"string"},"temporalWorkflowId":{"description":"Temporal workflow id for API-worker runs.","example":"background-task/user/daily-summary/api-trigger-123","nullable":true,"type":"string"},"trigger":{"description":"Trigger source.","enum":["manual","cron","window","event"],"example":"manual","type":"string"},"useCase":{"description":"High-level usage label.","example":"background-task","nullable":true,"type":"string"}},"required":["revision"],"type":"object"},"BackgroundTaskRunStatusResponse":{"description":"Compact polling response for one run.","properties":{"completedAt":{"description":"Run completion timestamp.","example":"2026-06-04T21:02:00Z","format":"date-time","nullable":true,"type":"string"},"error":{"description":"Terminal error, when present.","example":"","nullable":true,"type":"string"},"executor":{"description":"Execution backend.","enum":["desktop","api"],"example":"api","type":"string"},"lastHeartbeatAt":{"description":"Latest worker heartbeat/progress timestamp.","example":"2026-06-04T21:01:30Z","format":"date-time","nullable":true,"type":"string"},"progressMessage":{"description":"Progress message.","example":"Building API-native task artifact.","nullable":true,"type":"string"},"progressPercent":{"description":"Best-known progress for polling clients.","example":50,"nullable":true,"type":"integer"},"revision":{"description":"Current run revision.","example":2,"type":"integer"},"runId":{"description":"Cloud-visible run id.","example":"api-trigger-4a31958c-3a0a-4cb2-9361-ea563cd0477b","type":"string"},"slug":{"description":"Task slug.","example":"daily-summary","type":"string"},"startedAt":{"description":"Run start timestamp.","example":"2026-06-04T21:01:00Z","format":"date-time","nullable":true,"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["queued","running","succeeded","failed","stopped"],"example":"active","type":"string"},"temporalRunId":{"description":"Temporal run id for API-worker runs.","example":"00000000-0000-0000-0000-000000000001","nullable":true,"type":"string"},"temporalStatus":{"description":"Last mirrored Temporal status.","example":"Running","nullable":true,"type":"string"},"temporalWorkflowId":{"description":"Temporal workflow id for API-worker runs.","example":"background-task/user/daily-summary/api-trigger-123","nullable":true,"type":"string"}},"required":["runId","slug","status","executor","revision"],"type":"object"},"BackgroundTaskRunsResponse":{"description":"Run list for one task or the authenticated account.","properties":{"nextCursor":{"description":"RFC3339 cursor for the next page when more runs are available.","example":"2026-06-04T21:00:30Z","nullable":true,"type":"string"},"runs":{"description":"Runs ordered by server creation time.","items":{"$ref":"#/components/schemas/BackgroundTaskRun"},"type":"array"}},"required":["runs"],"type":"object"},"BackgroundTaskScheduleState":{"properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"last_due_at":{"format":"date-time","type":"string"},"last_evaluated_at":{"format":"date-time","type":"string"},"last_run_id":{"type":"string"},"last_triggered_at":{"format":"date-time","type":"string"},"lease_expires_at":{"format":"date-time","type":"string"},"lease_owner":{"type":"string"},"revision":{"type":"integer"},"schedule_key":{"type":"string"},"task":{"$ref":"#/components/schemas/BackgroundTask"},"trigger_type":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","trigger_type","schedule_key","last_run_id","lease_owner","revision","user","task"],"type":"object"},"BackgroundTaskSignalRequest":{"description":"Control signal sent to a Temporal-backed API-worker run.","properties":{"payload":{"additionalProperties":true,"description":"Optional signal payload. update_context can carry context/text/requestedContext for the next runtime checkpoint.","type":"object"},"signal":{"description":"Supported control signal.","enum":["pause","resume","update_context"],"example":"pause","type":"string"}},"required":["signal"],"type":"object"},"BackgroundTaskTemplate":{"description":"Built-in starter template for creating API-target background tasks with safe defaults.","properties":{"active":{"description":"Whether instantiated tasks are active by default.","example":true,"type":"boolean"},"description":{"description":"Short explanation of what the template does.","example":"Summarize new priority email and produce a short follow-up plan.","type":"string"},"executionTarget":{"description":"Default execution target.","enum":["api","desktop"],"example":"api","type":"string"},"instructions":{"description":"Default task instructions.","example":"Review recent important Gmail messages and produce a markdown digest.","type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","nullable":true,"type":"string"},"name":{"description":"Default task name.","example":"Inbox Digest","type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","nullable":true,"type":"string"},"requiredConnectors":{"description":"Connectors this template expects for full fidelity.","items":{"description":"Connector slug.","example":"google","type":"string"},"type":"array"},"slug":{"description":"Stable template slug.","example":"inbox-digest","type":"string"},"tags":{"description":"Template tags for UI grouping.","items":{"description":"Tag.","example":"gmail","type":"string"},"type":"array"},"taskSlug":{"description":"Default task slug used when instantiating this template.","example":"inbox-digest","type":"string"},"triggers":{"description":"Task trigger configuration mirrored from the desktop task.yaml. Common shapes include cron schedules, window schedules, or event subscriptions. Null clears the mirrored trigger config on PATCH.","example":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"nullable":true}},"required":["slug","taskSlug","name","description","instructions","active","executionTarget"],"type":"object"},"BackgroundTaskTemplateInstantiateRequest":{"description":"Overrides applied while creating a task from a built-in template. Omitted fields use template defaults.","properties":{"active":{"description":"Override active state.","example":true,"type":"boolean"},"executionTarget":{"description":"Execution target override.","enum":["desktop","api"],"example":"api","type":"string"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","nullable":true,"type":"string"},"name":{"description":"Task name override.","example":"Executive Inbox Digest","nullable":true,"type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","nullable":true,"type":"string"},"slug":{"description":"Task slug override. Defaults to template.taskSlug.","example":"exec-inbox","nullable":true,"type":"string"},"triggers":{"description":"Task trigger configuration mirrored from the desktop task.yaml. Common shapes include cron schedules, window schedules, or event subscriptions. Null clears the mirrored trigger config on PATCH.","example":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"nullable":true}},"type":"object"},"BackgroundTaskTemplatesResponse":{"description":"Built-in background task templates available to the authenticated user.","properties":{"templates":{"description":"Available task templates.","items":{"$ref":"#/components/schemas/BackgroundTaskTemplate"},"type":"array"}},"required":["templates"],"type":"object"},"BackgroundTaskTriggerRequest":{"description":"Queues a remote run request. The desktop sync loop claims queued runs and executes them locally.","properties":{"context":{"description":"Optional user-supplied execution context passed to the desktop when it claims the queued run.","example":"Run this now and focus on high-risk accounts.","nullable":true,"type":"string"},"trigger":{"description":"Trigger source for the queued run. Defaults to manual.","enum":["manual","cron","window","event"],"example":"manual","type":"string"}},"type":"object"},"BillingState":{"description":"Current plan, status, trial, and usage for the authenticated user.","properties":{"plan":{"description":"Billing plan slug.","enum":["free","starter","pro"],"example":"free","nullable":true,"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["active","trialing","past_due","canceled"],"example":"active","nullable":true,"type":"string"},"trialExpiresAt":{"description":"Trial expiry as RFC3339 when trialing; null otherwise.","example":"2026-07-01T00:00:00.000Z","nullable":true,"type":"string"},"usage":{"$ref":"#/components/schemas/BillingUsage"}},"required":["plan","status","trialExpiresAt","usage"],"type":"object"},"BillingUsage":{"description":"Credit usage shape parsed by the desktop billing package.","properties":{"availableCredits":{"description":"Credits remaining.","example":9875,"type":"integer"},"daily":{"$ref":"#/components/schemas/DailyCreditUsageBucket"},"monthly":{"$ref":"#/components/schemas/CreditUsageBucket"},"sanctionedCredits":{"description":"Total credits granted by the subscription.","example":10000,"type":"integer"},"usedCredits":{"description":"Total credits consumed against the subscription.","example":125,"type":"integer"}},"required":["sanctionedCredits","usedCredits","availableCredits","monthly","daily"],"type":"object"},"CloudEvent":{"description":"Stored cloud event. payload and routing appear only on the detail endpoint.","properties":{"dedupeKey":{"description":"Idempotency anchor.","example":"gmail:msg:msg_123","type":"string"},"eventType":{"description":"Provider-specific event type.","example":"email.received","nullable":true,"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"},"matchedTaskCount":{"description":"Tasks the router matched.","example":1,"type":"integer"},"occurredAt":{"description":"RFC3339 provider event time.","example":"2026-06-06T14:00:00Z","nullable":true,"type":"string"},"payload":{"additionalProperties":true,"description":"Decrypted normalized provider payload. Detail endpoint only.","type":"object"},"receivedAt":{"description":"RFC3339 API receipt time.","example":"2026-06-06T14:00:02Z","type":"string"},"routedAt":{"description":"RFC3339 router completion time.","example":"2026-06-06T14:00:09Z","nullable":true,"type":"string"},"routing":{"additionalProperties":true,"description":"Routing decision summary (threshold, prompt versions, per-task decisions). Detail endpoint only.","type":"object"},"routingStatus":{"description":"Routing status.","enum":["pending","routed","skipped","failed"],"example":"routed","type":"string"},"source":{"description":"Event source.","enum":["gmail","google_calendar","google_drive","slack","webhook","mcp","github","linear","stripe","internal"],"example":"gmail","type":"string"},"sourceAccountId":{"description":"Connected-account key.","example":"acct_google_primary","nullable":true,"type":"string"},"sourceEventId":{"description":"Provider-side event id.","example":"evt_123","nullable":true,"type":"string"},"subject":{"description":"Short title.","example":"Invoice #4821 dispute","nullable":true,"type":"string"},"text":{"description":"Human-readable gist.","example":"Acme disputed invoice #4821.","nullable":true,"type":"string"}},"required":["id","source","dedupeKey","routingStatus","receivedAt"],"type":"object"},"CloudEventIngestRequest":{"description":"Normalized cloud event envelope posted by internal services, tests, or the desktop (RFC 003).","properties":{"dedupeKey":{"description":"Required idempotency anchor, unique per (user, source).","example":"gmail:msg:msg_123","type":"string"},"eventType":{"description":"Provider-specific event type.","example":"email.received","nullable":true,"type":"string"},"occurredAt":{"description":"RFC3339 provider event time.","example":"2026-06-06T14:00:00Z","nullable":true,"type":"string"},"payload":{"additionalProperties":true,"description":"Full normalized provider object. Sealed at rest; returned only by the event detail endpoint.","type":"object"},"source":{"description":"Event source.","enum":["gmail","google_calendar","google_drive","slack","webhook","mcp","github","linear","stripe","internal"],"example":"internal","type":"string"},"sourceAccountId":{"description":"Connected-account key the event belongs to.","example":"acct_google_primary","nullable":true,"type":"string"},"sourceEventId":{"description":"Provider-side event id.","example":"evt_123","nullable":true,"type":"string"},"subject":{"description":"Short title used in UI and routing prompts.","example":"Invoice #4821 dispute","nullable":true,"type":"string"},"text":{"description":"Human-readable gist used in routing prompts.","example":"Acme disputed invoice #4821 for $18,000.","nullable":true,"type":"string"}},"required":["source","dedupeKey"],"type":"object"},"CloudEventIngestResponse":{"description":"Ingestion result. 202 for a fresh event; 200 with deduped=true for an idempotent replay.","properties":{"deduped":{"description":"Whether this post matched an existing (user, source, dedupeKey) event.","example":false,"type":"boolean"},"eventId":{"description":"Cloud event id.","example":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","type":"string"},"matchedTaskCount":{"description":"Tasks the router matched (populated once routed).","example":0,"type":"integer"},"routingStatus":{"description":"Routing status at response time.","enum":["pending","routed","skipped","failed"],"example":"pending","type":"string"}},"required":["eventId","routingStatus","deduped"],"type":"object"},"CloudEventListResponse":{"description":"Cloud event page ordered by receivedAt descending.","properties":{"events":{"description":"Events in this page (payload omitted).","items":{"$ref":"#/components/schemas/CloudEvent"},"type":"array"},"nextCursor":{"description":"Opaque cursor for the next page; empty when exhausted.","example":"2026-06-06T14:00:02.123456Z|0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","nullable":true,"type":"string"}},"required":["events"],"type":"object"},"CloudEventRun":{"description":"Run triggered by a cloud event.","properties":{"completedAt":{"description":"RFC3339 run completion time.","example":"2026-06-06T14:02:31Z","nullable":true,"type":"string"},"createdAt":{"description":"RFC3339 run creation time.","example":"2026-06-06T14:00:10Z","type":"string"},"executor":{"description":"Run executor.","enum":["api"],"example":"api","type":"string"},"runId":{"description":"Run id.","example":"event-7e0a1f2b","type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"taskSlug":{"description":"Slug of the task the run executed.","example":"acme-ar-watch","nullable":true,"type":"string"},"trigger":{"description":"Run trigger.","enum":["event"],"example":"event","type":"string"}},"required":["runId","status","trigger","executor","createdAt"],"type":"object"},"CloudEventRunsResponse":{"description":"Runs triggered by one cloud event.","properties":{"runs":{"description":"Linked runs.","items":{"$ref":"#/components/schemas/CloudEventRun"},"type":"array"}},"required":["runs"],"type":"object"},"Commitment":{"properties":{"acceptance":{"type":"string"},"beneficiary_participant_ref":{"type":"string"},"blocker":{"type":"string"},"completed_at":{"format":"date-time","type":"string"},"confidence":{"format":"double","type":"number"},"counterparty_participant_ref":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"current_event_version":{"type":"integer"},"direction":{"type":"string"},"due_at":{"format":"date-time","type":"string"},"due_phrase":{"type":"string"},"due_timezone":{"type":"string"},"events":{"items":{"$ref":"#/components/schemas/CommitmentEvent"},"type":"array"},"evidences":{"items":{"$ref":"#/components/schemas/RevenueEvidence"},"type":"array"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"incoming_dependencies":{"items":{"$ref":"#/components/schemas/CommitmentDependency"},"type":"array"},"outgoing_dependencies":{"items":{"$ref":"#/components/schemas/CommitmentDependency"},"type":"array"},"owner_participant_ref":{"type":"string"},"relationship":{"$ref":"#/components/schemas/Relationship"},"source_phrase":{"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"text":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"user_confirmed":{"type":"boolean"},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","direction","text","status","confidence","user_confirmed","acceptance","current_event_version","workspace","relationship","user"],"type":"object"},"CommitmentDependency":{"description":"An evidence-backed directed edge between two commitments.","properties":{"createdAt":{"description":"Creation time.","example":"2026-08-01T14:00:00Z","format":"date-time","type":"string"},"dependencyId":{"description":"Dependency id.","example":"8b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"evidenceRefs":{"description":"Evidence references.","items":{"description":"Reference.","example":"relationship-observation:ab12","type":"string"},"type":"array"},"fromCommitmentId":{"description":"Origin commitment id.","example":"8b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"kind":{"description":"Dependency semantics.","enum":["blocks","requires","supersedes"],"example":"blocks","type":"string"},"relationshipId":{"description":"Relationship id.","example":"8b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"toCommitmentId":{"description":"Target commitment id.","example":"8b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"}},"required":["dependencyId","relationshipId","fromCommitmentId","toCommitmentId","kind","evidenceRefs","createdAt"],"type":"object"},"CommitmentEvent":{"description":"One immutable event in a commitment transition stream.","properties":{"action":{"description":"Promised action at this event.","example":"Send the security packet.","type":"string"},"actorRef":{"description":"Actor reference.","example":"participant:owner","type":"string"},"actorType":{"description":"Transition authority.","enum":["user","source_fact","deterministic_rule","ai_candidate"],"example":"user","type":"string"},"beneficiaryParticipantRef":{"description":"Promise beneficiary.","example":"participant:beneficiary","type":"string"},"blocker":{"description":"Blocker detail.","example":"Waiting on legal.","type":"string"},"commitmentId":{"description":"Commitment id.","example":"26cdbdc9-d0fc-4f8c-8660-2f0d62cfef51","format":"uuid","type":"string"},"counterpartyParticipantRef":{"description":"Promise counterparty.","example":"participant:customer","type":"string"},"dueAt":{"description":"Resolved due time.","example":"2026-08-07T17:00:00Z","format":"date-time","type":"string"},"duePhrase":{"description":"Original due phrase.","example":"by Friday","type":"string"},"dueTimezone":{"description":"Due-time timezone.","example":"America/New_York","type":"string"},"eventId":{"description":"Event id.","example":"8b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"evidenceRefs":{"description":"Exact evidence references.","items":{"description":"Reference.","example":"relationship-observation:ab12","type":"string"},"type":"array"},"kind":{"description":"Transition kind.","enum":["proposed","internally_confirmed","offered","accepted","disputed","blocked","unblocked","due_date_changed","renegotiated","fulfilled","cancelled","superseded"],"example":"accepted","type":"string"},"occurredAt":{"description":"Event time.","example":"2026-08-01T14:00:00Z","format":"date-time","type":"string"},"ownerParticipantRef":{"description":"Promise owner.","example":"participant:owner","type":"string"},"reason":{"description":"Reason code for the ledger entry.","enum":["llm_call","llm_call_reserve","llm_settle","voice_tts","exa_search","grant","refund"],"example":"llm_settle","type":"string"},"sourceEventId":{"description":"Idempotent source event id.","example":"user-accept:commitment-1","type":"string"},"sourceObservationId":{"description":"Source observation id.","example":"relationship-observation:ab12","type":"string"},"supersedesCommitmentId":{"description":"Superseded commitment id.","example":"a13cf25b-d195-45f3-a665-3a38ba575392","format":"uuid","type":"string"},"version":{"minimum":1,"type":"integer"}},"required":["eventId","commitmentId","sourceEventId","version","kind","actorType","occurredAt","evidenceRefs"],"type":"object"},"ConfigResponse":{"description":"Public bootstrap values consumed by the desktop before sign-in.","properties":{"appUrl":{"description":"Browser-facing application origin.","example":"http://localhost:18080","type":"string"},"oauthClientId":{"description":"Pre-registered OAuth/OIDC client id. Empty means the desktop may fall back to dynamic registration.","example":"solomon-desktop-kind","type":"string"},"oidcIssuerUrl":{"description":"OIDC issuer the desktop signs into.","example":"http://localhost:18090","type":"string"},"supabaseUrl":{"description":"Compatibility alias for oidcIssuerUrl used by older desktop builds.","example":"http://localhost:18090","type":"string"},"websocketApiUrl":{"description":"Optional WebSocket API origin. Empty when not configured.","example":"","type":"string"}},"required":["appUrl","oidcIssuerUrl","supabaseUrl","websocketApiUrl","oauthClientId"],"type":"object"},"ConnectionAPIKeyRequest":{"description":"Stores a vendor-issued API key for an api_key connector.","properties":{"apiKey":{"description":"Vendor API key. Stored sealed at rest and never returned by connector list endpoints.","example":"example-vendor-key","type":"string"}},"required":["apiKey"],"type":"object"},"ConnectionClaimRequest":{"description":"Redeems a one-time connector OAuth ticket parked by /v1/connections/{name}/callback.","properties":{"state":{"description":"Opaque one-time OAuth state/session ticket.","example":"state_abc123","type":"string"}},"required":["state"],"type":"object"},"ConnectionConnectedResponse":{"description":"Connector connection result.","properties":{"connected":{"description":"Whether the connector is now connected.","example":true,"type":"boolean"}},"required":["connected"],"type":"object"},"ConnectionStartResponse":{"description":"OAuth authorize URL for a connector.","properties":{"authorize_url":{"description":"Browser URL the desktop opens to start the connector OAuth flow.","example":"https://oauth.solomon-ai.co/oauth2/auth?client_id=rowboat-api&state=...","type":"string"}},"required":["authorize_url"],"type":"object"},"Connector":{"description":"Connector entry shown by the desktop connector picker.","properties":{"authType":{"description":"Connector credential flow.","enum":["oauth","api_key"],"example":"oauth","type":"string"},"connected":{"description":"Whether the authenticated user has an active connection.","example":true,"type":"boolean"},"connectedAt":{"description":"RFC3339 connection timestamp when connected.","example":"2026-06-04T20:38:00Z","nullable":true,"type":"string"},"description":{"description":"Short product capability description.","example":"Banking, invoicing, dunning, transactions","type":"string"},"displayName":{"description":"Human-readable connector name.","example":"Canvas","type":"string"},"iconUrl":{"description":"Optional icon URL for UI display.","example":"https://example.com/icon.png","nullable":true,"type":"string"},"mcpTools":{"description":"Allowlisted upstream MCP tools and trust tiers for cloud runtime calls.","items":{"$ref":"#/components/schemas/MCPToolPolicy"},"type":"array"},"mcpUrl":{"description":"MCP endpoint the desktop should call after obtaining an MCP token. Empty for native SDK connectors.","example":"https://api.canvas.solomon-ai.co/v1/mcp","type":"string"},"name":{"description":"Stable connector slug.","example":"canvas","type":"string"},"nativeTools":{"description":"Allowlisted server-side native SDK tools and trust tiers.","items":{"$ref":"#/components/schemas/MCPToolPolicy"},"type":"array"},"scopes":{"description":"OAuth scopes granted or requested.","example":["invoices:read","customers:read"],"items":{"description":"Scope.","example":"invoices:read","type":"string"},"type":"array"},"templateBlocks":{"description":"Onboarding capability blocks shown when a user browses or connects this integration.","items":{"$ref":"#/components/schemas/IntegrationTemplateBlock"},"type":"array"},"transport":{"description":"Connector execution transport. MCP is the default; native uses server-side SDK tools.","enum":["mcp","native"],"example":"mcp","type":"string"}},"required":["name","displayName","description","mcpUrl","authType","connected"],"type":"object"},"ConnectorsResponse":{"description":"Connector registry plus per-user connection state.","properties":{"connectors":{"description":"Available connectors in configured order.","items":{"$ref":"#/components/schemas/Connector"},"type":"array"}},"required":["connectors"],"type":"object"},"ConversationClaim":{"description":"A material conversation claim anchored to exact words, time, speaker confidence, and capture caveats.","properties":{"captureCaveats":{"description":"Capture caveats.","items":{"description":"Caveat.","example":"Remote channel may contain multiple speakers.","type":"string"},"type":"array"},"confidence":{"description":"Claim confidence.","example":0.72,"type":"number"},"endMs":{"description":"End offset in milliseconds.","example":16000,"type":"integer"},"exactQuote":{"description":"Exact supporting transcript words.","example":"We are concerned security could delay the renewal.","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"},"kind":{"description":"Claim kind.","enum":["risk","objection","decision","milestone","sentiment","stakeholder","lifecycle","commitment"],"example":"risk","type":"string"},"material":{"description":"Whether the claim can affect state or action.","example":true,"type":"boolean"},"observationId":{"description":"Supporting immutable observation.","example":"6b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"speakerConfidence":{"description":"Speaker attribution confidence.","example":0.55,"type":"number"},"speakerId":{"description":"Meeting-scoped speaker id; never a persistent voiceprint.","example":"anonymous:remote-channel","type":"string"},"speakerLabel":{"description":"Current meeting-scoped speaker label.","example":"Other","type":"string"},"startMs":{"description":"Start offset in milliseconds.","example":12000,"type":"integer"},"stateDimension":{"description":"Projected state dimension when applicable.","example":"risk","type":"string"},"value":{"description":"Normalized claim value.","example":"Security review may delay renewal.","type":"string"}},"required":["id","kind","value","exactQuote","startMs","endMs","speakerId","speakerLabel","speakerConfidence","confidence","captureCaveats","material"],"type":"object"},"ConversationDeletionReceipt":{"description":"Immutable deletion request and per-target verification state. Pending device or provider targets keep the receipt partial.","properties":{"completedAt":{"description":"Time every required target was verified.","example":"2026-07-31T14:01:00Z","format":"date-time","nullable":true,"type":"string"},"legalHold":{"description":"Whether legal hold blocked deletion.","example":false,"type":"boolean"},"receiptId":{"description":"Idempotent request id.","example":"delete:ab12","type":"string"},"requestedAt":{"description":"Request time.","example":"2026-07-31T14:00:00Z","format":"date-time","type":"string"},"scopeRef":{"description":"Relationship scope.","example":"9c8dfa9b-a7b2-46ea-982c-622a914c00e5","type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["pending","blocked","partial","verified"],"example":"active","type":"string"},"targets":{"description":"Per-target outcomes.","items":{"description":"Deletion target outcome.","properties":{"attempts":{"description":"Attempts made.","example":1,"type":"integer"},"errorCode":{"description":"Bounded failure code.","example":"legal_hold","type":"string"},"status":{"description":"Target state.","enum":["pending","deleted","not_found","blocked","failed"],"example":"deleted","type":"string"},"target":{"description":"Deletion target.","enum":["local_recording","local_note","outbox","api_evidence","embedding","plan_share","provider"],"example":"api_evidence","type":"string"},"verificationHash":{"description":"Content-free verification hash.","example":"sha256:ab12","type":"string"}},"required":["target","status","attempts"],"type":"object"},"type":"array"}},"required":["receiptId","requestedAt","scopeRef","legalHold","status","targets"],"type":"object"},"ConversationGovernanceReceipt":{"description":"Capture, routing, retention, disclosure, legal-hold, deletion, and evidence-clip receipt stored beside a transcript.","properties":{"capturePolicy":{"description":"Capture policy in force.","example":"manual_capture","type":"string"},"capturedAt":{"description":"Capture time.","example":"2026-07-31T14:00:00Z","format":"date-time","type":"string"},"deletionOutcome":{"description":"Observed deletion outcome.","example":"scheduled_after_transcription","type":"string"},"evidenceClip":{"description":"Material audio evidence status; retained clips may only be encrypted.","enum":["not_retained","encrypted"],"example":"not_retained","type":"string"},"legalHold":{"description":"Whether deletion is blocked by legal hold.","example":false,"type":"boolean"},"participantDisclosure":{"description":"Recorded participant disclosure status.","example":"not_recorded","type":"string"},"receiptId":{"description":"Receipt id.","example":"governance:ab12","type":"string"},"region":{"description":"Processing region or boundary.","example":"local_device","type":"string"},"retention":{"description":"Retention policy.","example":"untilTranscribed","type":"string"},"routing":{"description":"Evidence routing path.","example":"local_transcription_to_oppulence","type":"string"}},"required":["receiptId","capturedAt","capturePolicy","routing","region","retention","participantDisclosure","legalHold","deletionOutcome","evidenceClip"],"type":"object"},"ConversationIntelligenceArtifact":{"properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"effective_at":{"format":"date-time","type":"string"},"evidence_refs":{"items":{"type":"string"},"type":"array"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"kind":{"type":"string"},"payload_hash":{"type":"string"},"payload_json":{"type":"string"},"relationship":{"$ref":"#/components/schemas/Relationship"},"stable_id":{"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"subject_ref":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"version":{"type":"integer"},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","kind","stable_id","version","effective_at","evidence_refs","payload_json","payload_hash","workspace","user"],"type":"object"},"ConversationReviewItem":{"description":"One evidence-backed proposed change requiring approve, correct, reject, or defer review.","properties":{"baselineVersion":{"description":"Pinned relationship-state version.","example":4,"type":"integer"},"batchId":{"description":"Idempotent review batch id.","example":"review:ab12","type":"string"},"before":{"additionalProperties":true,"description":"State pinned before conversation processing.","type":"object"},"caveats":{"description":"Extraction and capture caveats.","items":{"description":"Caveat.","example":"Speaker assignment requires review.","type":"string"},"type":"array"},"claimId":{"description":"Material claim id.","example":"claim:ab12","type":"string"},"confidence":{"description":"Current confidence.","example":0.55,"type":"number"},"currentValue":{"description":"Current inferred value.","example":"Other","type":"string"},"dependentActionIds":{"description":"Actions invalidated by rejection or correction.","items":{"description":"Action id.","example":"action:ab12","type":"string"},"type":"array"},"exactQuote":{"description":"Exact words under review.","example":"We are concerned.","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"},"kind":{"description":"Review kind.","enum":["word","speaker","entity","claim","capture"],"example":"speaker","type":"string"},"label":{"description":"Review prompt.","example":"Resolve the speaker for a material statement.","type":"string"},"observationId":{"description":"Supporting observation.","example":"6b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"proposedAfter":{"additionalProperties":true,"description":"Typed proposed value after this item.","type":"object"},"stateDimension":{"description":"Canonical state dimension affected by correction.","example":"risk","type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["pending_review","accepted","corrected","rejected","deferred"],"example":"active","type":"string"}},"required":["id","kind","label","currentValue","confidence","observationId"],"type":"object"},"CreditLedger":{"description":"Append-only credit grant, reservation, settlement, refund, or consumption entry.","properties":{"delta":{"description":"Credit delta. Negative values consume/reserve credits; positive values grant or refund credits.","example":-42,"type":"integer"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"reason":{"description":"Reason code for the ledger entry.","enum":["llm_call","llm_call_reserve","llm_settle","voice_tts","exa_search","grant","refund"],"example":"llm_settle","type":"string"},"request_id":{"description":"Idempotency and trace anchor for a metered request.","example":"9e2fb15a-936d-4f39-9372-73cfe0476ca8","format":"uuid","type":"string"},"ts":{"description":"Usage or ledger event timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","delta","reason","request_id","ts","user"],"type":"object"},"CreditUsageBucket":{"description":"Credit bucket totals. One credit is currently modeled as $0.0001 of usage.","properties":{"availableCredits":{"description":"Credits remaining in this bucket.","example":9875,"type":"integer"},"sanctionedCredits":{"description":"Credits granted to the user for this bucket.","example":10000,"type":"integer"},"usedCredits":{"description":"Credits consumed in this bucket.","example":125,"type":"integer"}},"required":["sanctionedCredits","usedCredits","availableCredits"],"type":"object"},"CurrentUser":{"description":"Authenticated Solomon AI user resolved from the bearer token.","properties":{"email":{"description":"Best-known WorkOS primary email for the user.","example":"user@example.com","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"}},"required":["id","email"],"type":"object"},"DailyCreditUsageBucket":{"description":"Daily credit bucket. The day is UTC.","properties":{"availableCredits":{"description":"Credits remaining after today's usage.","example":9975,"type":"integer"},"sanctionedCredits":{"description":"Credits granted to the user.","example":10000,"type":"integer"},"usageDay":{"description":"UTC day for the daily bucket, formatted YYYY-MM-DD.","example":"2026-06-04","type":"string"},"usedCredits":{"description":"Credits consumed since UTC midnight.","example":25,"type":"integer"}},"required":["sanctionedCredits","usedCredits","availableCredits","usageDay"],"type":"object"},"ErrorEnvelope":{"description":"RFC 9457 problem details returned by Solomon AI API handlers. code, requestId, and traceId are extension members.","properties":{"code":{"description":"Stable machine-readable error code.","example":"unauthorized","type":"string"},"detail":{"description":"Human-readable error detail.","example":"missing bearer token","type":"string"},"instance":{"description":"Optional occurrence URI.","example":"/v1/me","nullable":true,"type":"string"},"requestId":{"description":"Request id emitted by the API middleware.","example":"req-abc123","nullable":true,"type":"string"},"status":{"description":"HTTP status code.","example":401,"type":"integer"},"title":{"description":"Short HTTP-status summary.","example":"Unauthorized","type":"string"},"traceId":{"description":"OpenTelemetry trace id when tracing is active.","example":"4bf92f3577b34da6a3ce929d0e0e4736","nullable":true,"type":"string"},"type":{"description":"Problem type URI.","example":"https://api.rowboat.dev/problems/unauthorized","type":"string"}},"required":["type","title","status","code"],"type":"object"},"ExaSearchRequest":{"additionalProperties":true,"description":"Exa search request body. Solomon AI API applies a flat credit charge and forwards the JSON body unchanged to Exa /search.","properties":{"contents":{"additionalProperties":true,"description":"Optional Exa contents selector.","type":"object"},"excludeDomains":{"description":"Optional domain deny-list.","items":{"description":"Domain.","example":"spam.example","type":"string"},"type":"array"},"includeDomains":{"description":"Optional domain allow-list.","items":{"description":"Domain.","example":"example.com","type":"string"},"type":"array"},"numResults":{"description":"Maximum result count requested from Exa.","example":5,"type":"integer"},"query":{"description":"Natural-language or keyword search query.","example":"recent fintech accounts receivable trends","type":"string"},"type":{"description":"Exa search type, for example neural or keyword.","example":"neural","type":"string"}},"required":["query"],"type":"object"},"ExaSearchResponse":{"additionalProperties":true,"description":"Exa /search JSON response, proxied unchanged.","type":"object"},"GenericWebhookEventRequest":{"description":"Signed generic webhook event ingestion. Defaults source=webhook; connector/provider gateways may send source=mcp, github, linear, or stripe. The receiver resolves the owner from userId.","properties":{"dedupeKey":{"description":"Optional idempotency anchor. If omitted, sourceEventId is required and derives <source>:<sourceAccountId>:<sourceEventId>.","example":"webhook:zapier-acme-ar:evt_123","nullable":true,"type":"string"},"eventType":{"description":"Provider-specific event type.","example":"invoice.disputed","nullable":true,"type":"string"},"occurredAt":{"description":"RFC3339 provider event time.","example":"2026-06-06T14:00:00Z","nullable":true,"type":"string"},"payload":{"additionalProperties":true,"description":"Full provider object. Sealed at rest; returned only by the event detail endpoint.","type":"object"},"source":{"description":"Webhook source.","enum":["webhook","mcp","github","linear","stripe"],"example":"webhook","type":"string"},"sourceAccountId":{"description":"External account or webhook integration key.","example":"zapier-acme-ar","nullable":true,"type":"string"},"sourceEventId":{"description":"Provider-side event id. Used to derive dedupeKey when dedupeKey is omitted.","example":"evt_123","nullable":true,"type":"string"},"subject":{"description":"Short title used in UI and routing prompts. Defaults to eventType when omitted.","example":"Invoice #4821 dispute","nullable":true,"type":"string"},"text":{"description":"Human-readable gist used in routing prompts. Defaults to a compact payload summary when omitted.","example":"Acme disputed invoice #4821.","nullable":true,"type":"string"},"userId":{"description":"Rowboat user id (UUID) owning the event.","example":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5","type":"string"}},"required":["userId"],"type":"object"},"GoogleClaimRequest":{"description":"Redeems a one-time Google OAuth handoff ticket parked by /oauth/google/callback.","properties":{"session":{"description":"Opaque state/session ticket returned to the desktop deep link.","example":"state_abc123","type":"string"}},"required":["session"],"type":"object"},"GoogleRefreshRequest":{"description":"Refreshes a Google access token with the server-held OAuth client secret.","properties":{"refreshToken":{"description":"Google refresh token from a prior claim.","example":"1//refresh","type":"string"}},"required":["refreshToken"],"type":"object"},"GoogleWatch":{"properties":{"account_email":{"type":"string"},"channel_id":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"date-time","type":"string"},"history_id":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"kind":{"type":"string"},"last_error":{"type":"string"},"renew_claimed_at":{"format":"date-time","type":"string"},"resource_id":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","kind","account_email","expires_at","user"],"type":"object"},"GraphQLRequest":{"description":"GraphQL request envelope.","properties":{"operationName":{"description":"Optional operation name.","example":"ListUsers","nullable":true,"type":"string"},"query":{"description":"GraphQL query or mutation.","example":"{ users(first: 10) { edges { node { id email } } } }","type":"string"},"variables":{"additionalProperties":true,"description":"Optional GraphQL variables.","type":"object"}},"required":["query"],"type":"object"},"GraphQLResponse":{"description":"GraphQL response envelope.","properties":{"data":{"additionalProperties":true,"description":"GraphQL data result.","type":"object"},"errors":{"description":"GraphQL execution errors.","items":{"additionalProperties":true,"description":"GraphQL error.","type":"object"},"type":"array"}},"type":"object"},"HealthResponse":{"description":"Liveness probe response.","properties":{"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["ok"],"example":"active","type":"string"}},"required":["status"],"type":"object"},"HubSpotSearchObject":{"description":"Bounded HubSpot CRM record.","properties":{"archived":{"description":"Whether HubSpot archived the record.","example":false,"type":"boolean"},"createdAt":{"description":"Record creation timestamp.","example":"2026-07-31T12:00:00Z","nullable":true,"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"},"properties":{"additionalProperties":{"type":"string"},"type":"object"},"updatedAt":{"description":"Record update timestamp.","example":"2026-07-31T12:00:00Z","nullable":true,"type":"string"}},"required":["id","properties"],"type":"object"},"HubSpotSearchRequest":{"description":"Bounded search of the authenticated user's connected HubSpot CRM.","properties":{"limit":{"description":"Maximum records returned (1-25).","example":10,"type":"integer"},"objectType":{"description":"CRM object type.","enum":["contact","company","deal","ticket"],"example":"contact","type":"string"},"query":{"description":"HubSpot free-text search query.","example":"buyer@example.com","type":"string"}},"required":["objectType","query"],"type":"object"},"HubSpotSearchResponse":{"description":"Native HubSpot SDK search result.","properties":{"objectType":{"description":"Canonical CRM object type.","enum":["contact","company","deal","ticket"],"example":"contact","type":"string"},"results":{"description":"Bounded matching records.","items":{"$ref":"#/components/schemas/HubSpotSearchObject"},"type":"array"},"total":{"description":"Total matching HubSpot records.","example":1,"format":"int64","type":"integer"}},"required":["objectType","total","results"],"type":"object"},"IntegrationTemplateBlock":{"description":"User-facing integration onboarding capability block. Blocks describe what an integration unlocks; they are not executable workflow nodes.","properties":{"category":{"description":"UI grouping category.","example":"finance","type":"string"},"description":{"description":"Human-readable capability description.","example":"Look up invoices, customers, balances, and current payment status.","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"},"mcpTools":{"description":"MCP tools backing this capability for an MCP transport connector.","items":{"description":"MCP tool name.","example":"invoice.lookup","type":"string"},"type":"array"},"nativeTools":{"description":"Server-side SDK tools backing this capability for a native transport connector.","items":{"description":"Native tool name.","example":"connector.read.hubspot_search","type":"string"},"type":"array"},"requiredScopes":{"description":"OAuth scopes required by this capability.","items":{"description":"Scope.","example":"invoices:read","type":"string"},"type":"array"},"samplePrompt":{"description":"Optional prompt example for the onboarding UI.","example":"Show me the current invoice status for Acme.","nullable":true,"type":"string"},"title":{"description":"Short block title.","example":"Invoice context","type":"string"},"trustTier":{"description":"Highest trust tier needed by this capability.","enum":["read","write","act","money-moving"],"example":"read","type":"string"}},"required":["id","title","description","category","trustTier"],"type":"object"},"InternalCloudEventIngestRequest":{"description":"Server-to-server cloud event ingestion: the caller names the event owner explicitly.","properties":{"dedupeKey":{"description":"Required idempotency anchor.","example":"internal:job:42","type":"string"},"source":{"description":"Event source.","enum":["gmail","google_calendar","google_drive","slack","webhook","mcp","github","linear","stripe","internal"],"example":"internal","type":"string"},"userId":{"description":"Rowboat user id (UUID) owning the event.","example":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5","type":"string"}},"required":["userId","source","dedupeKey"],"type":"object"},"InternalInvalidateRequest":{"description":"Server-to-server force disconnect request.","properties":{"connector":{"description":"Connector slug.","example":"canvas","type":"string"},"workos_user_id":{"description":"WorkOS user id used to resolve bearer tokens into local users.","example":"user_01HABCDEF","type":"string"}},"required":["workos_user_id","connector"],"type":"object"},"InternalInvalidateResponse":{"description":"Force disconnect result.","properties":{"deleted":{"description":"Number of connection rows deleted. Omitted for unknown users.","example":1,"type":"integer"},"invalidated":{"description":"Always true on successful handling, including no-op unknown users.","example":true,"type":"boolean"}},"required":["invalidated"],"type":"object"},"LLMChatCompletionsRequest":{"additionalProperties":true,"description":"OpenAI-compatible chat completions request. rowboat-api requires model, gates credits, rewrites routable model ids, and passes through other fields.","properties":{"max_tokens":{"description":"Maximum output tokens to reserve and request from the upstream.","example":1024,"type":"integer"},"messages":{"description":"Conversation messages.","items":{"$ref":"#/components/schemas/LLMChatMessage"},"type":"array"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","type":"string"},"response_format":{"additionalProperties":true,"description":"OpenAI-compatible response_format object forwarded untouched.","type":"object"},"stream":{"description":"When true, rowboat-api streams server-sent events and asks the upstream to include usage.","example":true,"type":"boolean"},"temperature":{"description":"Sampling temperature forwarded to the upstream.","example":0.2,"type":"number"},"tool_choice":{"description":"OpenAI-compatible tool choice. String or object values are forwarded untouched.","example":"auto"},"tools":{"description":"OpenAI-compatible tool definitions forwarded untouched.","items":{"additionalProperties":true,"description":"Tool definition.","type":"object"},"type":"array"}},"required":["model","messages"],"type":"object"},"LLMChatMessage":{"additionalProperties":true,"description":"OpenAI-compatible chat message. Additional OpenAI fields are passed through.","properties":{"content":{"description":"Text, multimodal content array, or provider-specific content payload."},"name":{"description":"Optional participant name.","example":"analyst","nullable":true,"type":"string"},"role":{"description":"Message role.","enum":["system","user","assistant","tool"],"example":"user","type":"string"}},"required":["role","content"],"type":"object"},"LLMCompletionsRequest":{"additionalProperties":true,"description":"OpenAI-compatible legacy completions request.","properties":{"max_tokens":{"description":"Maximum output tokens to reserve and request.","example":512,"type":"integer"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","type":"string"},"prompt":{"description":"Prompt string or prompt array forwarded to the upstream.","example":"Summarize this account."},"stream":{"description":"When true, stream upstream completion events.","example":false,"type":"boolean"},"temperature":{"description":"Sampling temperature forwarded to the upstream.","example":0.2,"type":"number"}},"required":["model","prompt"],"type":"object"},"LLMEmbeddingsRequest":{"additionalProperties":true,"description":"OpenAI-compatible embeddings request.","properties":{"dimensions":{"description":"Optional embedding dimensions for models that support it.","example":1536,"type":"integer"},"encoding_format":{"description":"Embedding encoding format forwarded to the upstream.","example":"float","nullable":true,"type":"string"},"input":{"description":"Input string or array of strings.","example":["customer invoice","payment risk"]},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","type":"string"}},"required":["model","input"],"type":"object"},"LLMGatewayResponse":{"additionalProperties":true,"description":"OpenAI-compatible upstream response. For streaming calls, the same endpoint returns text/event-stream chunks.","type":"object"},"LLMModel":{"description":"Routable model id exposed to the desktop.","properties":{"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"}},"required":["id"],"type":"object"},"LLMModelsResponse":{"description":"Catalog of priced and routable model ids.","properties":{"data":{"description":"Available models sorted by id.","items":{"$ref":"#/components/schemas/LLMModel"},"type":"array"}},"required":["data"],"type":"object"},"LLMUsage":{"description":"One LLM gateway call with token counts, settled credit cost, request id, and feature telemetry.","properties":{"agent_name":{"description":"Optional x-solomon-agent-name header captured for cost allocation.","example":"desktop-assistant","type":"string"},"cost_units":{"description":"Settled credit cost for the request.","example":8,"type":"integer"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"input_tokens":{"description":"Input tokens reported by the upstream or estimated by Solomon AI API.","example":812,"type":"integer"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","type":"string"},"output_tokens":{"description":"Output tokens reported by the upstream.","example":210,"type":"integer"},"request_id":{"description":"Idempotency and trace anchor for a metered request.","example":"9e2fb15a-936d-4f39-9372-73cfe0476ca8","format":"uuid","type":"string"},"sub_use_case":{"description":"Optional x-solomon-sub-use-case header captured for cost allocation.","example":"invoice-summary","type":"string"},"ts":{"description":"Usage or ledger event timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"use_case":{"description":"Optional x-solomon-use-case header captured for cost allocation.","example":"collections","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","model","input_tokens","output_tokens","cost_units","request_id","ts","user"],"type":"object"},"LLMUsageHistory":{"description":"Audit history for LLMUsage rows.","properties":{"agent_name":{"description":"Optional x-solomon-agent-name header captured for cost allocation.","example":"desktop-assistant","type":"string"},"cost_units":{"description":"Settled credit cost for the request.","example":8,"type":"integer"},"history_time":{"description":"Timestamp when this history record was written.","example":"2026-06-04T20:40:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"input_tokens":{"description":"Input tokens reported by the upstream or estimated by Solomon AI API.","example":812,"type":"integer"},"model":{"description":"Desktop-facing LLM model id.","example":"openai/gpt-4.1-mini","type":"string"},"operation":{"description":"Mutation operation that produced this history row.","enum":["INSERT","UPDATE","DELETE"],"example":"UPDATE","type":"string"},"output_tokens":{"description":"Output tokens reported by the upstream.","example":210,"type":"integer"},"ref":{"description":"UUID of the source row represented by a history row.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"request_id":{"description":"Idempotency and trace anchor for a metered request.","example":"9e2fb15a-936d-4f39-9372-73cfe0476ca8","format":"uuid","type":"string"},"sub_use_case":{"description":"Optional x-solomon-sub-use-case header captured for cost allocation.","example":"invoice-summary","type":"string"},"ts":{"description":"Usage or ledger event timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"use_case":{"description":"Optional x-solomon-use-case header captured for cost allocation.","example":"collections","type":"string"}},"required":["id","history_time","operation","model","input_tokens","output_tokens","cost_units","request_id","ts"],"type":"object"},"MCPConnection":{"description":"Per-user connector credential state for MCP products. Stores sealed OAuth refresh tokens or API keys.","properties":{"api_key_encrypted":{"description":"Sealed vendor API key. Sensitive internal storage field; never returned by desktop endpoints.","format":"byte","type":"string","writeOnly":true},"audience":{"description":"OAuth token audience for the connector.","example":"canvas-api","type":"string"},"connected_at":{"description":"Timestamp when the connector was connected.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"connector":{"description":"Connector slug.","example":"canvas","type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"last_used_at":{"description":"Timestamp when the connector credential was last minted or used.","example":"2026-06-04T20:45:00Z","format":"date-time","type":"string"},"refresh_token_encrypted":{"description":"Sealed refresh token. Sensitive internal storage field; never returned by desktop endpoints.","format":"byte","type":"string","writeOnly":true},"scopes":{"description":"OAuth scopes granted or requested.","example":["invoices:read","customers:read"],"items":{"type":"string"},"type":"array"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","connector","audience","user"],"type":"object"},"MCPConnectionHistory":{"description":"Audit history for MCPConnection rows.","properties":{"api_key_encrypted":{"description":"Sealed vendor API key. Sensitive internal storage field; never returned by desktop endpoints.","format":"byte","type":"string","writeOnly":true},"audience":{"description":"OAuth token audience for the connector.","example":"canvas-api","type":"string"},"connected_at":{"description":"Timestamp when the connector was connected.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"connector":{"description":"Connector slug.","example":"canvas","type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"date-time","type":"string"},"history_time":{"description":"Timestamp when this history record was written.","example":"2026-06-04T20:40:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"last_used_at":{"description":"Timestamp when the connector credential was last minted or used.","example":"2026-06-04T20:45:00Z","format":"date-time","type":"string"},"operation":{"description":"Mutation operation that produced this history row.","enum":["INSERT","UPDATE","DELETE"],"example":"UPDATE","type":"string"},"ref":{"description":"UUID of the source row represented by a history row.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"refresh_token_encrypted":{"description":"Sealed refresh token. Sensitive internal storage field; never returned by desktop endpoints.","format":"byte","type":"string","writeOnly":true},"scopes":{"description":"OAuth scopes granted or requested.","example":["invoices:read","customers:read"],"items":{"type":"string"},"type":"array"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"}},"required":["id","created_at","updated_at","history_time","operation","connector","audience"],"type":"object"},"MCPTokenResponse":{"description":"Short-lived credential and target URL for calling a connector MCP endpoint.","properties":{"access_token":{"description":"Bearer token or API key for the connector's MCP endpoint.","example":"mcp_access_token","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"int64","type":"integer"},"mcpUrl":{"description":"Connector MCP endpoint URL.","example":"https://api.canvas.solomon-ai.co/v1/mcp","type":"string"},"token_type":{"description":"Token type, usually Bearer.","example":"Bearer","type":"string"}},"required":["access_token","token_type","mcpUrl"],"type":"object"},"MCPToolPolicy":{"description":"Allowlisted upstream MCP tool metadata.","properties":{"name":{"description":"Upstream MCP tool name.","example":"customer.lookup","type":"string"},"trustTier":{"description":"Runtime trust tier for this tool.","enum":["read","write","act","money-moving"],"example":"read","type":"string"}},"required":["name","trustTier"],"type":"object"},"MailBodyCache":{"properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","type":"string"},"provider_message_id":{"type":"string"},"sealed_body":{"format":"byte","type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","provider","provider_message_id","sealed_body","expires_at","user"],"type":"object"},"MailMessageMeta":{"properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"direction":{"type":"string"},"from_addr":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"labels":{"items":{"type":"string"},"type":"array"},"occurred_at":{"format":"date-time","type":"string"},"provider_message_id":{"type":"string"},"subject":{"type":"string"},"thread":{"$ref":"#/components/schemas/MailThread"},"to_addr":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","provider_message_id","occurred_at","direction","labels","thread","user"],"type":"object"},"MailSignal":{"properties":{"classification":{"type":"string"},"computed_at":{"format":"date-time","type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"embedding":{"format":"byte","type":"string"},"embedding_model":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"summary":{"type":"string"},"thread":{"$ref":"#/components/schemas/MailThread"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","classification","computed_at","thread","user"],"type":"object"},"MailThread":{"properties":{"account_domain":{"type":"string"},"counterparty_email":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"inbound_count":{"type":"integer"},"labels":{"items":{"type":"string"},"type":"array"},"last_activity_at":{"format":"date-time","type":"string"},"last_direction":{"type":"string"},"message_count":{"type":"integer"},"messages":{"items":{"$ref":"#/components/schemas/MailMessageMeta"},"type":"array"},"outbound_count":{"type":"integer"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","type":"string"},"provider_thread_id":{"type":"string"},"relationship":{"$ref":"#/components/schemas/Relationship"},"reply_state":{"type":"string"},"signal":{"$ref":"#/components/schemas/MailSignal"},"subject":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","provider","provider_thread_id","labels","reply_state","message_count","outbound_count","inbound_count","user"],"type":"object"},"MeResponse":{"description":"Response for GET /v1/me.","properties":{"billing":{"$ref":"#/components/schemas/BillingState"},"user":{"$ref":"#/components/schemas/CurrentUser","description":"User that owns this row."}},"required":["user","billing"],"type":"object"},"MeetingMinuteUsage":{"properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"period":{"type":"string"},"reserved_seconds":{"type":"integer"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"used_seconds":{"type":"integer"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","period","used_seconds","reserved_seconds","user"],"type":"object"},"OAuthConnection":{"description":"Long-lived third-party OAuth connection such as Google. Refresh tokens are sealed before storage.","properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"external_account_id":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","type":"string"},"refresh_token_encrypted":{"description":"Sealed refresh token. Sensitive internal storage field; never returned by desktop endpoints.","format":"byte","type":"string","writeOnly":true},"scopes":{"description":"OAuth scopes granted or requested.","example":["invoices:read","customers:read"],"items":{"type":"string"},"type":"array"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","provider","refresh_token_encrypted","user"],"type":"object"},"OAuthConnectionHistory":{"description":"Audit history for OAuthConnection rows.","properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"external_account_id":{"type":"string"},"history_time":{"description":"Timestamp when this history record was written.","example":"2026-06-04T20:40:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"operation":{"description":"Mutation operation that produced this history row.","enum":["INSERT","UPDATE","DELETE"],"example":"UPDATE","type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","type":"string"},"ref":{"description":"UUID of the source row represented by a history row.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"refresh_token_encrypted":{"description":"Sealed refresh token. Sensitive internal storage field; never returned by desktop endpoints.","format":"byte","type":"string","writeOnly":true},"scopes":{"description":"OAuth scopes granted or requested.","example":["invoices:read","customers:read"],"items":{"type":"string"},"type":"array"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"}},"required":["id","created_at","updated_at","history_time","operation","provider","refresh_token_encrypted"],"type":"object"},"OAuthPending":{"description":"Ephemeral one-time OAuth handoff ticket with sealed payload and expiry.","properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"payload_encrypted":{"description":"AES-GCM sealed OAuth handoff payload. Internal storage field.","format":"byte","type":"string","writeOnly":true},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","type":"string"},"state":{"description":"Opaque one-time OAuth state/session ticket.","example":"state_abc123","type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"}},"required":["id","created_at","updated_at","state","provider","payload_encrypted","expires_at"],"type":"object"},"OAuthTokenBundle":{"description":"OAuth token bundle returned to the desktop.","properties":{"access_token":{"description":"Provider access token.","example":"example-access-token","type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"int64","type":"integer"},"refresh_token":{"description":"Provider refresh token, present on claim when the provider issues one.","example":"1//refresh","nullable":true,"type":"string"},"scope":{"description":"Space-delimited OAuth scopes.","example":"openid email profile https://www.googleapis.com/auth/gmail.readonly","nullable":true,"type":"string"},"token_type":{"description":"OAuth token type.","example":"Bearer","nullable":true,"type":"string"}},"required":["access_token","expires_at"],"type":"object"},"PolicyDecisionSnapshot":{"properties":{"action":{"$ref":"#/components/schemas/RevenueAction"},"action_revision":{"type":"integer"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"crm_json":{"type":"string"},"evaluated_at":{"format":"date-time","type":"string"},"evidence_refs":{"items":{"type":"string"},"type":"array"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"outbound_lead_id":{"type":"string"},"reason_codes":{"items":{"type":"string"},"type":"array"},"research_json":{"type":"string"},"response_hash":{"type":"string"},"revision_hash":{"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"suppression_json":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"verification_json":{"type":"string"},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","action_revision","revision_hash","status","reason_codes","evidence_refs","evaluated_at","expires_at","response_hash","workspace","action","user"],"type":"object"},"PreConsentRequest":{"description":"Ory pre-consent webhook payload mapped by ops.","properties":{"connector":{"description":"Connector slug.","example":"canvas","nullable":true,"type":"string"},"requested_audience":{"description":"Requested token audience. Used to resolve connector when connector is absent.","example":"canvas-api","nullable":true,"type":"string"},"subject":{"description":"Fallback subject/user id from Ory.","example":"user_01HABCDEF","nullable":true,"type":"string"},"workos_user_id":{"description":"WorkOS user id used to resolve bearer tokens into local users.","example":"user_01HABCDEF","type":"string"}},"required":["requested_audience"],"type":"object"},"PreConsentResponse":{"description":"Connector entitlement decision.","properties":{"allow":{"description":"Whether Ory should continue the consent flow.","example":true,"type":"boolean"},"upsell":{"$ref":"#/components/schemas/Upsell"}},"required":["allow"],"type":"object"},"ReadyResponse":{"description":"Readiness probe response.","properties":{"failed":{"description":"Name of the failed readiness check when status is not_ready.","example":"database","nullable":true,"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["ready","not_ready"],"example":"active","type":"string"}},"required":["status"],"type":"object"},"ReconnectErrorEnvelope":{"description":"Problem details used when an upstream refresh token is invalid and the desktop must reconnect.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["reconnect_required"],"example":"reconnect_required","type":"string"},"detail":{"description":"Human-readable error detail.","example":"Google reports invalid_grant; user must reconnect.","type":"string"},"reconnectRequired":{"description":"Whether the desktop should force the user through a new OAuth connection flow.","example":true,"type":"boolean"},"requestId":{"description":"Request id emitted by the API middleware.","example":"req-abc123","nullable":true,"type":"string"},"status":{"description":"HTTP status code.","example":409,"type":"integer"},"title":{"description":"Short HTTP-status summary.","example":"Conflict","type":"string"},"traceId":{"description":"OpenTelemetry trace id when tracing is active.","example":"4bf92f3577b34da6a3ce929d0e0e4736","nullable":true,"type":"string"},"type":{"description":"Problem type URI.","example":"https://api.rowboat.dev/problems/reconnect_required","type":"string"}},"required":["type","title","status","code","reconnectRequired"],"type":"object"},"Relationship":{"properties":{"account_domain":{"type":"string"},"actions":{"items":{"$ref":"#/components/schemas/RevenueAction"},"type":"array"},"assertions":{"items":{"$ref":"#/components/schemas/RelationshipAssertion"},"type":"array"},"commitment_dependencies":{"items":{"$ref":"#/components/schemas/CommitmentDependency"},"type":"array"},"commitment_events":{"items":{"$ref":"#/components/schemas/CommitmentEvent"},"type":"array"},"commitments":{"items":{"$ref":"#/components/schemas/Commitment"},"type":"array"},"conversation_intelligence_artifacts":{"items":{"$ref":"#/components/schemas/ConversationIntelligenceArtifact"},"type":"array"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"display_name":{"type":"string"},"engagement":{"type":"string"},"evidences":{"items":{"$ref":"#/components/schemas/RevenueEvidence"},"type":"array"},"health":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"identities":{"items":{"$ref":"#/components/schemas/RelationshipIdentity"},"type":"array"},"kind":{"type":"string"},"last_changed_at":{"format":"date-time","type":"string"},"last_touch_at":{"format":"date-time","type":"string"},"lifecycle":{"type":"string"},"mail_threads":{"items":{"$ref":"#/components/schemas/MailThread"},"type":"array"},"milestones":{"items":{"type":"string"},"type":"array"},"next_action":{"type":"string"},"next_action_at":{"format":"date-time","type":"string"},"observations":{"items":{"$ref":"#/components/schemas/RelationshipObservation"},"type":"array"},"outbound_account_ref":{"type":"string"},"outbound_lead_id":{"type":"string"},"participants":{"items":{"$ref":"#/components/schemas/RelationshipParticipant"},"type":"array"},"primary_email":{"type":"string"},"resource_refs":{"items":{"type":"string"},"type":"array"},"risks":{"items":{"type":"string"},"type":"array"},"sentiment":{"type":"string"},"snapshots":{"items":{"$ref":"#/components/schemas/RelationshipStateSnapshot"},"type":"array"},"state_reason":{"type":"string"},"state_version":{"type":"integer"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"summary":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","kind","display_name","resource_refs","status","lifecycle","engagement","sentiment","health","state_version","risks","milestones","workspace","user"],"type":"object"},"RelationshipAssertion":{"properties":{"confidence":{"format":"double","type":"number"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"dimension":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"observation":{"$ref":"#/components/schemas/RelationshipObservation"},"reason":{"description":"Reason code for the ledger entry.","enum":["llm_call","llm_call_reserve","llm_settle","voice_tts","exa_search","grant","refund"],"example":"llm_settle","type":"string"},"relationship":{"$ref":"#/components/schemas/Relationship"},"source_type":{"type":"string"},"supersedes_assertion_id":{"type":"string"},"supporting_observation_ids":{"items":{"type":"string"},"type":"array"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"valid_from":{"format":"date-time","type":"string"},"value":{"type":"string"},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","dimension","value","source_type","confidence","valid_from","supporting_observation_ids","workspace","relationship","user"],"type":"object"},"RelationshipCommitment":{"description":"An open or completed promise attached to the relationship.","properties":{"confidence":{"description":"Extraction confidence.","example":0.94,"type":"number"},"direction":{"description":"Who owes the commitment.","example":"us_to_them","type":"string"},"dueAt":{"description":"Due time.","example":"2026-07-22T17:00:00Z","format":"date-time","nullable":true,"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"text":{"description":"Commitment text.","example":"Send the security packet.","type":"string"},"userConfirmed":{"description":"Whether a human confirmed it.","example":false,"type":"boolean"}},"required":["id","direction","text","status","confidence","userConfirmed"],"type":"object"},"RelationshipIdentity":{"properties":{"confidence":{"format":"double","type":"number"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"first_seen_at":{"format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"kind":{"type":"string"},"last_seen_at":{"format":"date-time","type":"string"},"provider":{"description":"Provider slug. Depending on the row this may be an OAuth provider, LLM provider, or execution backend.","example":"openai","type":"string"},"relationship":{"$ref":"#/components/schemas/Relationship"},"source":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","kind","confidence","first_seen_at","last_seen_at","workspace","relationship","user"],"type":"object"},"RelationshipIntelligence":{"description":"Derived trust surface for a relationship: conversation claims, focused review, exact delta, governance, contradictions, and live cue cards.","properties":{"claims":{"description":"Material quote-backed claims.","items":{"$ref":"#/components/schemas/ConversationClaim"},"type":"array"},"contradictionCases":{"description":"Typed durable conflicts.","items":{"additionalProperties":true,"description":"Contradiction case.","type":"object"},"type":"array"},"deletionReceipts":{"description":"Deletion status and verification.","items":{"$ref":"#/components/schemas/ConversationDeletionReceipt"},"type":"array"},"delta":{"additionalProperties":true,"description":"Credit delta. Negative values consume/reserve credits; positive values grant or refund credits.","example":-42,"type":"object"},"effectivePolicy":{"$ref":"#/components/schemas/ResolvedConversationPolicy"},"governanceDecisions":{"description":"Immutable checkpoint decisions.","items":{"additionalProperties":true,"description":"Governance decision.","type":"object"},"type":"array"},"governanceReceipts":{"description":"Transcript governance receipts.","items":{"$ref":"#/components/schemas/ConversationGovernanceReceipt"},"type":"array"},"liveCues":{"description":"Account-history cue cards for the next/live meeting.","items":{"additionalProperties":true,"description":"Cue card.","type":"object"},"type":"array"},"mutualActionPlans":{"description":"Revision-bound bilateral plans.","items":{"additionalProperties":true,"description":"Mutual action plan.","type":"object"},"type":"array"},"recommendationEvaluations":{"description":"Immutable contextual ranking factors.","items":{"additionalProperties":true,"description":"Recommendation evaluation.","type":"object"},"type":"array"},"recoveryEvaluations":{"description":"Bounded commitment recovery evaluations.","items":{"additionalProperties":true,"description":"Recovery evaluation.","type":"object"},"type":"array"},"reviewItems":{"description":"Only low-confidence review items.","items":{"$ref":"#/components/schemas/ConversationReviewItem"},"type":"array"}},"required":["claims","reviewItems","governanceReceipts","delta","liveCues","contradictionCases","recoveryEvaluations","recommendationEvaluations","mutualActionPlans","effectivePolicy","governanceDecisions","deletionReceipts"],"type":"object"},"RelationshipObservation":{"description":"Immutable, idempotent provider evidence used to project relationship state.","properties":{"contentHash":{"description":"Hash of summary, facts, and sealed payload.","example":"ab12cd34","type":"string"},"eventType":{"description":"Normalized event type.","example":"commitment_created","type":"string"},"externalId":{"description":"Provider event id.","example":"message-123","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"normalizedFacts":{"additionalProperties":true,"description":"Provider-neutral normalized facts.","type":"object"},"occurredAt":{"description":"Provider occurrence time.","example":"2026-07-18T17:30:00Z","format":"date-time","type":"string"},"receivedAt":{"description":"Ingestion time.","example":"2026-07-18T17:31:00Z","format":"date-time","type":"string"},"source":{"description":"Evidence source.","example":"gmail","type":"string"},"sourceAccountId":{"description":"Provider account id.","example":"me@company.com","type":"string"},"sourceVersion":{"description":"Provider event version.","example":"1","type":"string"},"summary":{"description":"Bounded evidence summary.","example":"We promised to send the security packet.","type":"string"}},"required":["id","source","externalId","sourceVersion","eventType","occurredAt","receivedAt","normalizedFacts","contentHash"],"type":"object"},"RelationshipParticipant":{"description":"A person participating in the relationship, resolved across provider identities.","properties":{"active":{"description":"Whether the participant is active.","example":true,"type":"boolean"},"displayName":{"description":"Display name.","example":"Avery Chen","type":"string"},"email":{"description":"Best-known WorkOS primary email for the user.","example":"user@example.com","type":"string"},"externalRefs":{"description":"Provider identity references.","items":{"description":"External reference.","example":"hubspot:contact:123","type":"string"},"type":"array"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"role":{"description":"Relationship role.","example":"champion","type":"string"},"title":{"description":"Current title.","example":"VP Operations","type":"string"}},"required":["id","displayName","role","active","externalRefs"],"type":"object"},"RelationshipSourceStatus":{"description":"Freshness and failure state for one relationship evidence source.","properties":{"lastError":{"description":"Bounded provider error.","example":"","type":"string"},"lastObservationAt":{"description":"Newest provider event seen.","example":"2026-07-26T11:58:00Z","format":"date-time","nullable":true,"type":"string"},"lastSuccessAt":{"description":"Last successful ingestion.","example":"2026-07-26T12:00:00Z","format":"date-time","nullable":true,"type":"string"},"source":{"description":"Source name.","example":"gmail","type":"string"},"sourceAccountId":{"description":"Provider account id.","example":"me@company.com","type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"}},"required":["source","sourceAccountId","status"],"type":"object"},"RelationshipStateSnapshot":{"description":"Immutable projection snapshot created only when material relationship state changes.","properties":{"assertionIds":{"description":"Assertions selected by deterministic precedence.","items":{"description":"Assertion id.","example":"assertion-123","type":"string"},"type":"array"},"changedDimensions":{"description":"Material dimensions that changed.","items":{"description":"Dimension.","example":"health","type":"string"},"type":"array"},"createdAt":{"description":"Snapshot creation time.","example":"2026-07-25T16:00:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"state":{"additionalProperties":true,"description":"Opaque one-time OAuth state/session ticket.","example":"state_abc123","type":"object"},"version":{"description":"Relationship state version.","example":4,"type":"integer"}},"required":["id","version","state","changedDimensions","assertionIds","createdAt"],"type":"object"},"ResolvedConversationPolicy":{"description":"Monotonically resolved conversation policy with every contributing layer recorded.","properties":{"capture":{"description":"Capture rule.","enum":["deny","require_consent","allow"],"example":"require_consent","type":"string"},"externalShare":{"description":"Whether externally scoped plan sharing is allowed.","example":true,"type":"boolean"},"legalHold":{"description":"Whether required deletion is blocked.","example":false,"type":"boolean"},"modelRoute":{"description":"Most permissive model route allowed.","enum":["local_only","region_restricted","hosted_allowed"],"example":"local_only","type":"string"},"policyVersion":{"description":"Hash-bound effective policy version.","example":"policy:ab12","type":"string"},"publishEvidence":{"description":"Whether shared evidence publication is allowed.","example":true,"type":"boolean"},"redactionClasses":{"description":"Classes removed at outbound boundaries.","items":{"description":"Redaction class.","example":"personal_identifier","type":"string"},"type":"array"},"resolvedAt":{"description":"Resolution time.","example":"2026-07-31T14:00:00Z","format":"date-time","type":"string"},"retentionDays":{"description":"Maximum retention in days.","example":30,"type":"integer"},"sourceLayerIds":{"description":"Policy layers that contributed.","items":{"description":"Layer id.","example":"workspace:default","type":"string"},"type":"array"}},"required":["capture","modelRoute","publishEvidence","externalShare","retentionDays","redactionClasses","legalHold","policyVersion","sourceLayerIds","resolvedAt"],"type":"object"},"RevenueAction":{"description":"One Revenue Action Queue item. State is split into independent dimensions: queue triage, policy preflight, approval, and execution. Every edit creates a new revision and invalidates the previous policy decision and approval.","properties":{"actionType":{"description":"Action type.","enum":["warm_follow_up","proposal_nudge","referral_reconnect","customer_risk","meeting_follow_up","meeting_recap","crm_update","follow_up_task","calendar_hold","commitment_rescue"],"example":"warm_follow_up","type":"string"},"approvalStatus":{"description":"Approval state, bound to the exact revision and decision.","enum":["pending","approved","rejected"],"example":"pending","type":"string"},"approvedAt":{"description":"Approval time.","example":"2026-07-12T12:05:00Z","format":"date-time","nullable":true,"type":"string"},"approvedRevision":{"description":"Revision the approval is bound to.","example":1,"type":"integer"},"channel":{"description":"Delivery channel.","enum":["email","slack","call","crm_task","crm","task","calendar"],"example":"email","type":"string"},"createdAt":{"description":"Creation time.","example":"2026-07-12T12:00:00Z","format":"date-time","type":"string"},"detector":{"description":"Detector that produced the action.","enum":["requested_follow_up_due","unanswered_proposal","waiting_on_me","dormant_warm_opportunity","neglected_referral","former_customer_reconnect","conversation_action_pack","commitment_due","manual"],"example":"manual","type":"string"},"dismissReason":{"description":"Dismissal reason label.","example":"already_handled","type":"string"},"dueAt":{"description":"Due time.","example":"2026-07-15T00:00:00Z","format":"date-time","nullable":true,"type":"string"},"evidence":{"description":"Exact supporting evidence available in the approval UI.","items":{"description":"Action evidence.","properties":{"excerpt":{"description":"Exact supporting words.","example":"We are concerned security could delay renewal.","type":"string"},"externalEvidenceRefs":{"description":"Observation, timestamp, and speaker references.","items":{"description":"Reference.","example":"timestamp:12000-16000","type":"string"},"type":"array"},"id":{"description":"Evidence id.","example":"4b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"occurredAt":{"description":"Evidence time.","example":"2026-07-31T14:00:00Z","format":"date-time","type":"string"},"source":{"description":"Evidence source.","example":"meeting","type":"string"},"sourceRecordId":{"description":"Source record id.","example":"oppulence:session-42:claim:claim-risk","type":"string"}},"required":["id","source","sourceRecordId","occurredAt","externalEvidenceRefs"],"type":"object"},"type":"array"},"executedAt":{"description":"Execution time.","example":"2026-07-12T12:06:00Z","format":"date-time","nullable":true,"type":"string"},"executionError":{"description":"Bounded execution error.","example":"","type":"string"},"executionMode":{"description":"Draft lands in the operator's mailbox; send requires a passed unexpired decision and a linked workspace.","enum":["draft","send"],"example":"draft","type":"string"},"executionOwner":{"description":"Exactly one owner may execute a revision.","enum":["rowboat","outbound"],"example":"rowboat","type":"string"},"executionStatus":{"description":"Execution state. A lost provider result is ambiguous, never auto-resent.","enum":["pending","requested","sent","failed","ambiguous","cancelled"],"example":"pending","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"policyStatus":{"description":"Preflight state. Facade unavailability keeps pending (fail closed).","enum":["pending","passed","review_required","blocked","stale"],"example":"pending","type":"string"},"priorityComponents":{"additionalProperties":true,"description":"Per-component priority breakdown; every component is stored and shown.","type":"object"},"priorityScore":{"description":"Explainable priority score (0-100).","example":82,"type":"integer"},"proposedMessage":{"description":"Proposed message body.","example":"Hi Jordan — you asked me to circle back this month...","type":"string"},"proposedSubject":{"description":"Proposed email subject.","example":"Following up as promised","type":"string"},"providerMessageId":{"description":"Provider message id after execution.","example":"msg_01","type":"string"},"providerThreadId":{"description":"Provider thread id after execution.","example":"thread_01","type":"string"},"queueStatus":{"description":"Operator triage state.","enum":["open","snoozed","dismissed","handled"],"example":"open","type":"string"},"reason":{"description":"Reason code for the ledger entry.","enum":["llm_call","llm_call_reserve","llm_settle","voice_tts","exa_search","grant","refund"],"example":"llm_settle","type":"string"},"recipientEmail":{"description":"Recipient email address.","example":"buyer@example.com","type":"string"},"reconciliationAttempts":{"description":"Number of bounded provider lookups performed.","example":1,"type":"integer"},"reconciliationCheckedAt":{"description":"Most recent provider lookup time.","example":"2026-07-12T12:07:00Z","format":"date-time","nullable":true,"type":"string"},"reconciliationError":{"description":"Bounded provider lookup error.","example":"","type":"string"},"reconciliationNextAt":{"description":"Next scheduled read-only lookup time.","example":"2026-07-12T12:12:00Z","format":"date-time","nullable":true,"type":"string"},"reconciliationStatus":{"description":"Read-only provider reconciliation state for an ambiguous write.","enum":["pending","found","not_found","error","manual_review"],"example":"pending","type":"string"},"relationshipId":{"description":"Owning relationship id.","example":"9c8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"revision":{"description":"Current revision number.","example":1,"type":"integer"},"revisionHash":{"description":"Canonical hash of the revision content.","example":"sha256:ab12...","type":"string"},"senderAccountRef":{"description":"Sender account reference.","example":"gmail:me@company.com","type":"string"},"snoozedUntil":{"description":"Snooze wake time.","example":"2026-07-20T09:00:00Z","format":"date-time","nullable":true,"type":"string"},"updatedAt":{"description":"Last update time.","example":"2026-07-12T12:06:00Z","format":"date-time","type":"string"}},"required":["id","actionType","channel","detector","revision","revisionHash","reason","priorityScore","queueStatus","policyStatus","approvalStatus","executionStatus","executionOwner","executionMode","evidence"],"type":"object"},"RevenueActionRevision":{"properties":{"action":{"$ref":"#/components/schemas/RevenueAction"},"action_type":{"type":"string"},"assigned_user_id":{"format":"uuid","type":"string"},"channel":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"created_by":{"format":"uuid","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"proposed_message":{"type":"string"},"proposed_subject":{"type":"string"},"reason":{"description":"Reason code for the ledger entry.","enum":["llm_call","llm_call_reserve","llm_settle","voice_tts","exa_search","grant","refund"],"example":"llm_settle","type":"string"},"recipient_email":{"type":"string"},"revision":{"type":"integer"},"revision_hash":{"type":"string"},"sender_account_ref":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","revision","revision_hash","action_type","channel","action","user"],"type":"object"},"RevenueDigest":{"description":"The proactive digest content: the top open loops plus running impact counts. This is what the scheduled digest email is built from.","properties":{"generatedAt":{"description":"When composed.","example":"2026-07-23T09:00:00Z","format":"date-time","type":"string"},"handled":{"description":"Actions handled.","example":20,"type":"integer"},"meetingsBooked":{"description":"Meetings booked.","example":2,"type":"integer"},"openCount":{"description":"Total open actions.","example":8,"type":"integer"},"replied":{"description":"Replies observed.","example":6,"type":"integer"},"top":{"description":"Highest-priority open loops.","items":{"description":"Digest action.","properties":{"detector":{"description":"Human detector label.","example":"Unanswered proposal","type":"string"},"priority":{"description":"Priority score.","example":82,"type":"integer"},"reason":{"description":"Evidence-backed reason.","example":"You sent a proposal 10 days ago with no reply.","type":"string"},"recipient":{"description":"Recipient email.","example":"buyer@example.com","type":"string"}},"type":"object"},"type":"array"}},"required":["generatedAt","openCount"],"type":"object"},"RevenueEvidence":{"properties":{"actions":{"items":{"$ref":"#/components/schemas/RevenueAction"},"type":"array"},"commitments":{"items":{"$ref":"#/components/schemas/Commitment"},"type":"array"},"content_hash":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"excerpt":{"type":"string"},"external_evidence_refs":{"items":{"type":"string"},"type":"array"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"observed_at":{"format":"date-time","type":"string"},"occurred_at":{"format":"date-time","type":"string"},"payload_ciphertext":{"format":"byte","type":"string"},"relationships":{"items":{"$ref":"#/components/schemas/Relationship"},"type":"array"},"source":{"type":"string"},"source_account_id":{"type":"string"},"source_message_id":{"type":"string"},"source_record_id":{"type":"string"},"source_uri":{"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","source","source_record_id","content_hash","occurred_at","observed_at","external_evidence_refs","workspace","user"],"type":"object"},"RevenueImpact":{"description":"Aggregate ROI picture for the caller's revenue queue: how many open loops were surfaced, how they were triaged, how many were acted on, and what came back.","properties":{"approved":{"description":"Actions approved.","example":18,"type":"integer"},"byDetector":{"description":"Per-detector contribution.","items":{"description":"Detector stat.","properties":{"detector":{"description":"Detector.","example":"unanswered_proposal","type":"string"},"handled":{"description":"Handled from this detector.","example":7,"type":"integer"},"surfaced":{"description":"Surfaced by this detector.","example":12,"type":"integer"}},"type":"object"},"type":"array"},"dismissed":{"description":"Actions dismissed.","example":11,"type":"integer"},"executed":{"description":"Actions executed (draft created or email sent).","example":16,"type":"integer"},"handled":{"description":"Actions marked handled.","example":20,"type":"integer"},"lost":{"description":"Deals marked lost.","example":1,"type":"integer"},"meetingRate":{"description":"Meeting rate = meetings / executed; null with no denominator.","example":0.12,"nullable":true,"type":"number"},"meetingsBooked":{"description":"Meetings booked.","example":2,"type":"integer"},"open":{"description":"Actions currently open.","example":8,"type":"integer"},"outcomes":{"additionalProperties":true,"description":"Raw outcome-kind counts.","type":"object"},"replied":{"description":"Replies observed.","example":6,"type":"integer"},"replyRate":{"description":"Reply rate = replied / executed; null with no denominator.","example":0.38,"nullable":true,"type":"number"},"snoozed":{"description":"Actions snoozed.","example":3,"type":"integer"},"surfaced":{"description":"Total actions ever surfaced.","example":42,"type":"integer"},"won":{"description":"Deals marked won.","example":1,"type":"integer"}},"required":["surfaced","open","handled","approved","executed"],"type":"object"},"RevenueLeakScan":{"description":"One bounded historical scan over connected sources (Gmail first). Detectors are deterministic; counts, errors, and freshness make runs incremental and auditable.","properties":{"actionsCreated":{"description":"New queue actions created.","example":5,"type":"integer"},"candidatesSeen":{"description":"Detector candidates found.","example":7,"type":"integer"},"completedAt":{"description":"Completion time.","example":"2026-07-23T12:00:40Z","format":"date-time","nullable":true,"type":"string"},"error":{"description":"Bounded failure reason.","example":"","type":"string"},"evidencesCreated":{"description":"New evidence rows recorded.","example":5,"type":"integer"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"lookbackDays":{"description":"Historical lookback in days.","example":90,"type":"integer"},"mode":{"description":"Workspace mode at scan time.","enum":["local","linked"],"example":"local","type":"string"},"relationshipsCreated":{"description":"New relationships recorded.","example":3,"type":"integer"},"sourceFreshnessAt":{"description":"Newest source timestamp observed (incremental cursor).","example":"2026-07-22T09:00:00Z","format":"date-time","nullable":true,"type":"string"},"startedAt":{"description":"Start time.","example":"2026-07-23T12:00:00Z","format":"date-time","nullable":true,"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["pending","running","completed","failed"],"example":"active","type":"string"},"threadsSeen":{"description":"Threads examined.","example":42,"type":"integer"}},"required":["id","status","mode","lookbackDays"],"type":"object"},"RevenueOutboxEvent":{"properties":{"action_id":{"format":"uuid","type":"string"},"attempts":{"type":"integer"},"causation_id":{"type":"string"},"correlation_id":{"type":"string"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"delivery_status":{"type":"string"},"event_type":{"type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"idempotency_key":{"type":"string"},"last_error":{"type":"string"},"next_attempt_at":{"format":"date-time","type":"string"},"occurred_at":{"format":"date-time","type":"string"},"payload_json":{"type":"string"},"schema_version":{"type":"integer"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","event_type","schema_version","idempotency_key","occurred_at","delivery_status","attempts","workspace","user"],"type":"object"},"RevenueOutcome":{"description":"One observed action outcome, append-only and idempotent on (action, source, sourceEventId).","properties":{"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"kind":{"description":"Outcome kind.","enum":["sent","delivered","bounced","replied","meeting_booked","won","lost","dismissed","bad_recommendation","deal_advanced","onboarding_progressed","renewed","escalated","churned","corrected"],"example":"replied","type":"string"},"occurredAt":{"description":"When the outcome occurred.","example":"2026-07-12T14:00:00Z","format":"date-time","type":"string"},"source":{"description":"Observing source.","enum":["gmail","calendar","crm","user","outbound","slack","meeting","task"],"example":"gmail","type":"string"},"sourceEventId":{"description":"Source event id used for deduplication.","example":"msg_01","type":"string"}},"required":["id","kind","source","sourceEventId","occurredAt"],"type":"object"},"RevenuePolicyDecision":{"description":"Immutable OutboundConsole preflight decision for one exact action revision. Rowboat snapshots the decision; it never composes one.","properties":{"crm":{"additionalProperties":true,"description":"CRM sub-result snapshot; unknown when the connector is unavailable.","type":"object"},"evaluatedAt":{"description":"Evaluation time.","example":"2026-07-12T12:00:00Z","format":"date-time","type":"string"},"expiresAt":{"description":"Decision expiry; expired decisions must be re-evaluated before approval or execution.","example":"2026-07-13T12:00:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"reasonCodes":{"description":"Bounded reason codes.","items":{"description":"Reason code.","example":"suppression.opted_out","type":"string"},"type":"array"},"research":{"additionalProperties":true,"description":"Research sub-result snapshot.","type":"object"},"revision":{"description":"Action revision the decision is about.","example":1,"type":"integer"},"revisionHash":{"description":"Revision hash the decision is bound to.","example":"sha256:ab12...","type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["passed","review_required","blocked"],"example":"active","type":"string"},"suppression":{"additionalProperties":true,"description":"Suppression sub-result snapshot.","type":"object"},"verification":{"additionalProperties":true,"description":"Verification sub-result snapshot.","type":"object"}},"required":["id","revision","revisionHash","status","evaluatedAt","expiresAt"],"type":"object"},"RevenueRelationship":{"description":"Canonical, living relationship state projected from append-only evidence. CRM and communication systems remain evidence sources; this object is the shared model rendered by web and desktop.","properties":{"accountDomain":{"description":"Account domain.","example":"example.com","type":"string"},"displayName":{"description":"Human display name.","example":"Jordan Buyer","type":"string"},"engagement":{"description":"Direction of engagement.","enum":["unknown","increasing","steady","declining","dormant"],"example":"declining","type":"string"},"health":{"description":"Explainable health state; never a magic score.","enum":["unknown","healthy","needs_attention","critical"],"example":"needs_attention","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"kind":{"description":"Relationship kind.","enum":["person","company","customer","opportunity","referral","partner"],"example":"person","type":"string"},"lastChangedAt":{"description":"Last material state change.","example":"2026-07-25T16:00:00Z","format":"date-time","nullable":true,"type":"string"},"lastTouchAt":{"description":"Last observed touch.","example":"2026-04-10T15:00:00Z","format":"date-time","nullable":true,"type":"string"},"lifecycle":{"description":"Commercial lifecycle.","enum":["prospect","evaluation","contracting","onboarding","active_customer","renewal","churned","former_customer"],"example":"evaluation","type":"string"},"milestones":{"description":"Reached relationship milestones.","items":{"description":"Milestone.","example":"Proposal shared.","type":"string"},"type":"array"},"nextAction":{"description":"Recommended next action.","example":"Confirm the security review owner.","type":"string"},"nextActionAt":{"description":"Next planned action.","example":"2026-07-01T00:00:00Z","format":"date-time","nullable":true,"type":"string"},"openActions":{"description":"Open queue actions for this relationship.","example":1,"type":"integer"},"primaryEmail":{"description":"Primary email address.","example":"buyer@example.com","type":"string"},"risks":{"description":"Current relationship risks.","items":{"description":"Risk.","example":"Security review has no owner.","type":"string"},"type":"array"},"sentiment":{"description":"Observed sentiment.","enum":["unknown","positive","mixed","negative"],"example":"mixed","type":"string"},"stateReason":{"description":"Evidence-backed explanation of the projected state.","example":"Security review was promised, but no owner or meeting exists.","type":"string"},"stateVersion":{"description":"Monotonic projection version.","example":4,"type":"integer"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["active","dormant","closed","archived"],"example":"active","type":"string"},"summary":{"description":"Bounded relationship summary.","example":"Asked for pricing in April; wants a follow-up in July.","type":"string"}},"required":["id","kind","displayName","status","lifecycle","engagement","sentiment","health","stateVersion","risks","milestones"],"type":"object"},"RevenueWorkspace":{"description":"Mapping between the Rowboat tenant and the canonical OutboundConsole workspace. Local mode has no link: observation and draft-only execution work while preflight and sends stay disabled.","properties":{"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"lastVerifiedAt":{"description":"When the link was last verified.","example":"2026-07-12T12:00:00Z","format":"date-time","nullable":true,"type":"string"},"mode":{"description":"Workspace mode.","enum":["local","linked"],"example":"local","type":"string"},"outboundOrganizationId":{"description":"OutboundConsole organization id.","example":"org_01ABC","type":"string"},"outboundWorkspaceId":{"description":"OutboundConsole workspace id.","example":"ws_01ABC","type":"string"},"preflightAvailable":{"description":"Whether policy preflight can run (linked and active).","example":false,"type":"boolean"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","enum":["active","disconnected","repair_required"],"example":"active","type":"string"}},"required":["id","mode","status","preflightAvailable"],"type":"object"},"RevenueWorkspaceMember":{"properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"outbound_account_id":{"type":"string"},"role":{"type":"string"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."},"workspace":{"$ref":"#/components/schemas/RevenueWorkspace"}},"required":["id","created_at","updated_at","role","status","workspace","user"],"type":"object"},"RevisionConflictEnvelope":{"description":"Revision conflict returned when the caller edits a stale task, artifact, or run revision. Clients should refetch, merge, and retry with currentRevision.","properties":{"code":{"description":"Stable machine-readable conflict code.","enum":["conflict"],"example":"conflict","type":"string"},"currentRevision":{"description":"Current server revision for the resource that rejected the write.","example":3,"type":"integer"},"detail":{"description":"Human-readable conflict detail.","enum":["revision conflict"],"example":"revision conflict","type":"string"},"requestId":{"description":"Request id emitted by the API middleware.","example":"req-abc123","nullable":true,"type":"string"},"status":{"description":"HTTP status code.","example":409,"type":"integer"},"title":{"description":"Short HTTP-status summary.","example":"Conflict","type":"string"},"traceId":{"description":"OpenTelemetry trace id when tracing is active.","example":"4bf92f3577b34da6a3ce929d0e0e4736","nullable":true,"type":"string"},"type":{"description":"Problem type URI.","example":"https://api.rowboat.dev/problems/conflict","type":"string"}},"required":["type","title","status","code","currentRevision"],"type":"object"},"SlackClaimRequest":{"description":"Slack install session ticket redemption.","properties":{"session":{"description":"State ticket from the solomon-ai://oauth/slack/done deep link.","example":"state_abc123","type":"string"}},"required":["session"],"type":"object"},"SlackClaimResponse":{"description":"Connected Slack workspace metadata. The bot token is server-held and never returned.","properties":{"botUserId":{"description":"Bot user id in the workspace.","example":"U0BOT","nullable":true,"type":"string"},"connected":{"description":"Whether the workspace connection was stored.","example":true,"type":"boolean"},"scope":{"description":"Granted bot scopes, comma-separated.","example":"channels:history,channels:read","nullable":true,"type":"string"},"teamId":{"description":"Slack workspace (team) id — the key Events API deliveries resolve against.","example":"T0EXAMPLE","type":"string"},"teamName":{"description":"Workspace display name.","example":"Acme","nullable":true,"type":"string"}},"required":["connected","teamId"],"type":"object"},"SlackThreadMessage":{"description":"Slack thread message metadata returned to desktop chat.","properties":{"bot_id":{"description":"Slack bot id when present.","example":"B01234567","nullable":true,"type":"string"},"text":{"description":"Slack message text.","example":"Can you summarize this?","nullable":true,"type":"string"},"ts":{"description":"Usage or ledger event timestamp.","example":"2026-06-04T20:38:00Z","nullable":true,"type":"string"},"user":{"description":"User that owns this row.","example":"U01234567","nullable":true,"type":"string"}},"type":"object"},"SlackThreadPostRequest":{"description":"Post an approved Slack reply into a connected managed thread.","properties":{"channel":{"description":"Slack channel id.","example":"C01234567","type":"string"},"teamId":{"description":"Slack workspace/team id.","example":"T0EXAMPLE","type":"string"},"text":{"description":"Slack message text to post.","example":"I can take this one.","type":"string"},"threadTs":{"description":"Slack thread timestamp. The reply is posted under this thread.","example":"1700000000.000100","type":"string"}},"required":["teamId","channel","threadTs","text"],"type":"object"},"SlackThreadPostResponse":{"description":"Slack reply post result. The bot token and message text are never returned.","properties":{"channel":{"description":"Slack channel id.","example":"C01234567","type":"string"},"ok":{"description":"Whether Slack accepted the post.","example":true,"type":"boolean"},"teamId":{"description":"Slack workspace/team id.","example":"T0EXAMPLE","type":"string"},"threadTs":{"description":"Slack thread timestamp.","example":"1700000000.000100","type":"string"}},"required":["ok","teamId","channel","threadTs"],"type":"object"},"SlackThreadReadRequest":{"description":"Read a Slack thread from a connected managed workspace.","properties":{"channel":{"description":"Slack channel id.","example":"C01234567","type":"string"},"limit":{"description":"Max messages to return. Defaults to 50, max 200.","example":50,"nullable":true,"type":"integer"},"teamId":{"description":"Slack workspace/team id.","example":"T0EXAMPLE","type":"string"},"threadTs":{"description":"Slack thread timestamp. For a top-level message, use the message ts.","example":"1700000000.000100","type":"string"}},"required":["teamId","channel","threadTs"],"type":"object"},"SlackThreadReadResponse":{"description":"Slack thread messages read through the server-held Slack app token.","properties":{"channel":{"description":"Slack channel id.","example":"C01234567","type":"string"},"messages":{"description":"Slack thread messages.","items":{"$ref":"#/components/schemas/SlackThreadMessage"},"type":"array"},"teamId":{"description":"Slack workspace/team id.","example":"T0EXAMPLE","type":"string"},"threadTs":{"description":"Slack thread timestamp.","example":"1700000000.000100","type":"string"}},"required":["teamId","channel","threadTs","messages"],"type":"object"},"SlackWorkspace":{"description":"Connected Slack workspace metadata. Credentials are server-held and never returned.","properties":{"connectedAt":{"description":"Connection creation time.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"scopes":{"description":"OAuth scopes granted or requested.","example":["invoices:read","customers:read"],"items":{"description":"Slack OAuth scope.","example":"channels:history","type":"string"},"type":"array"},"teamId":{"description":"Slack workspace (team) id — the key Events API deliveries resolve against.","example":"T0EXAMPLE","type":"string"},"teamName":{"description":"Workspace display name when available.","example":"Acme","nullable":true,"type":"string"}},"required":["teamId"],"type":"object"},"SlackWorkspacesResponse":{"description":"Connected Slack workspaces for the authenticated user.","properties":{"workspaces":{"description":"Connected Slack workspaces.","items":{"$ref":"#/components/schemas/SlackWorkspace"},"type":"array"}},"required":["workspaces"],"type":"object"},"Subscription":{"description":"User billing plan, status, trial expiry, Stripe identifiers, and credit grant.","properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"plan":{"description":"Billing plan slug.","enum":["free","starter","pro"],"example":"free","type":"string"},"sanctioned_credits":{"description":"Credits granted by the current subscription.","example":10000,"type":"integer"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"stripe_customer_id":{"description":"Stripe customer id when billing is backed by Stripe.","example":"cus_123","type":"string"},"stripe_subscription_id":{"description":"Stripe subscription id when billing is backed by Stripe.","example":"sub_123","type":"string"},"trial_expires_at":{"description":"Trial expiry timestamp when the user is trialing.","example":"2026-07-01T00:00:00Z","format":"date-time","nullable":true,"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User","description":"User that owns this row."}},"required":["id","created_at","updated_at","plan","status","sanctioned_credits","user"],"type":"object"},"SubscriptionHistory":{"description":"Audit history for Subscription rows.","properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"history_time":{"description":"Timestamp when this history record was written.","example":"2026-06-04T20:40:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"operation":{"description":"Mutation operation that produced this history row.","enum":["INSERT","UPDATE","DELETE"],"example":"UPDATE","type":"string"},"plan":{"description":"Billing plan slug.","enum":["free","starter","pro"],"example":"free","type":"string"},"ref":{"description":"UUID of the source row represented by a history row.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"sanctioned_credits":{"description":"Credits granted by the current subscription.","example":10000,"type":"integer"},"status":{"description":"Lifecycle/status slug. Subscription rows use billing states; background task runs use queued/running/succeeded/failed/stopped.","example":"active","type":"string"},"stripe_customer_id":{"description":"Stripe customer id when billing is backed by Stripe.","example":"cus_123","type":"string"},"stripe_subscription_id":{"description":"Stripe subscription id when billing is backed by Stripe.","example":"sub_123","type":"string"},"trial_expires_at":{"description":"Trial expiry timestamp when the user is trialing.","example":"2026-07-01T00:00:00Z","format":"date-time","nullable":true,"type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"}},"required":["id","created_at","updated_at","history_time","operation","plan","status","sanctioned_credits"],"type":"object"},"Upsell":{"description":"Upgrade instruction returned when a connector requires a higher plan.","properties":{"message":{"description":"Human-readable upgrade copy.","example":"Upgrade to pro to connect Canvas","type":"string"},"requiredPlan":{"description":"Minimum plan required.","enum":["starter","pro"],"example":"pro","type":"string"}},"required":["requiredPlan","message"],"type":"object"},"User":{"description":"Local mirror of a WorkOS identity. Upserted when a verified bearer token is first seen.","properties":{"action_outcomes":{"items":{"$ref":"#/components/schemas/ActionOutcome"},"type":"array"},"action_proposals":{"items":{"$ref":"#/components/schemas/ActionProposal"},"type":"array"},"agent_approvals":{"items":{"$ref":"#/components/schemas/AgentApproval"},"type":"array"},"agent_definitions":{"items":{"$ref":"#/components/schemas/AgentDefinition"},"type":"array"},"agent_session_events":{"items":{"$ref":"#/components/schemas/AgentSessionEvent"},"type":"array"},"agent_sessions":{"items":{"$ref":"#/components/schemas/AgentSession"},"type":"array"},"agent_tool_calls":{"items":{"$ref":"#/components/schemas/AgentToolCall"},"type":"array"},"agent_tool_result_blobs":{"items":{"$ref":"#/components/schemas/AgentToolResultBlob"},"type":"array"},"agent_turns":{"items":{"$ref":"#/components/schemas/AgentTurn"},"type":"array"},"approval_tokens":{"items":{"$ref":"#/components/schemas/ApprovalToken"},"type":"array"},"background_task_artifacts":{"description":"Background task artifact mirrors owned by the user.","items":{"$ref":"#/components/schemas/BackgroundTaskArtifact"},"type":"array"},"background_task_run_events":{"description":"Background task run event mirrors owned by the user.","items":{"$ref":"#/components/schemas/BackgroundTaskRunEvent"},"type":"array"},"background_task_runs":{"description":"Background task run mirrors owned by the user.","items":{"$ref":"#/components/schemas/BackgroundTaskRun"},"type":"array"},"background_task_schedule_states":{"items":{"$ref":"#/components/schemas/BackgroundTaskScheduleState"},"type":"array"},"background_tasks":{"description":"Background task mirrors owned by the user.","items":{"$ref":"#/components/schemas/BackgroundTask"},"type":"array"},"cloud_events":{"items":{"$ref":"#/components/schemas/CloudEvent"},"type":"array"},"commitment_dependencies":{"items":{"$ref":"#/components/schemas/CommitmentDependency"},"type":"array"},"commitment_events":{"items":{"$ref":"#/components/schemas/CommitmentEvent"},"type":"array"},"commitments":{"items":{"$ref":"#/components/schemas/Commitment"},"type":"array"},"conversation_intelligence_artifacts":{"items":{"$ref":"#/components/schemas/ConversationIntelligenceArtifact"},"type":"array"},"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"email":{"description":"Best-known WorkOS primary email for the user.","example":"user@example.com","type":"string"},"google_watches":{"items":{"$ref":"#/components/schemas/GoogleWatch"},"type":"array"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"ledger_entries":{"description":"Append-only credit ledger entries for the user.","items":{"$ref":"#/components/schemas/CreditLedger"},"type":"array"},"llm_usages":{"description":"LLM usage rows for the user.","items":{"$ref":"#/components/schemas/LLMUsage"},"type":"array"},"mail_body_caches":{"items":{"$ref":"#/components/schemas/MailBodyCache"},"type":"array"},"mail_message_metas":{"items":{"$ref":"#/components/schemas/MailMessageMeta"},"type":"array"},"mail_signals":{"items":{"$ref":"#/components/schemas/MailSignal"},"type":"array"},"mail_threads":{"items":{"$ref":"#/components/schemas/MailThread"},"type":"array"},"mcp_connections":{"description":"MCP connector connections for the user.","items":{"$ref":"#/components/schemas/MCPConnection"},"type":"array"},"meeting_minute_usages":{"items":{"$ref":"#/components/schemas/MeetingMinuteUsage"},"type":"array"},"oauth_connections":{"description":"Third-party OAuth connections for the user.","items":{"$ref":"#/components/schemas/OAuthConnection"},"type":"array"},"policy_decision_snapshots":{"items":{"$ref":"#/components/schemas/PolicyDecisionSnapshot"},"type":"array"},"relationship_assertions":{"items":{"$ref":"#/components/schemas/RelationshipAssertion"},"type":"array"},"relationship_identities":{"items":{"$ref":"#/components/schemas/RelationshipIdentity"},"type":"array"},"relationship_observations":{"items":{"$ref":"#/components/schemas/RelationshipObservation"},"type":"array"},"relationship_participants":{"items":{"$ref":"#/components/schemas/RelationshipParticipant"},"type":"array"},"relationship_source_statuses":{"items":{"$ref":"#/components/schemas/RelationshipSourceStatus"},"type":"array"},"relationship_state_snapshots":{"items":{"$ref":"#/components/schemas/RelationshipStateSnapshot"},"type":"array"},"relationships":{"items":{"$ref":"#/components/schemas/Relationship"},"type":"array"},"revenue_action_revisions":{"items":{"$ref":"#/components/schemas/RevenueActionRevision"},"type":"array"},"revenue_actions":{"items":{"$ref":"#/components/schemas/RevenueAction"},"type":"array"},"revenue_evidences":{"items":{"$ref":"#/components/schemas/RevenueEvidence"},"type":"array"},"revenue_leak_scans":{"items":{"$ref":"#/components/schemas/RevenueLeakScan"},"type":"array"},"revenue_outbox_events":{"items":{"$ref":"#/components/schemas/RevenueOutboxEvent"},"type":"array"},"revenue_workspace_members":{"items":{"$ref":"#/components/schemas/RevenueWorkspaceMember"},"type":"array"},"revenue_workspaces":{"items":{"$ref":"#/components/schemas/RevenueWorkspace"},"type":"array"},"subscription":{"$ref":"#/components/schemas/Subscription","description":"The user's billing subscription."},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"workos_org_id":{"description":"Optional WorkOS organization id for B2B/workspace contexts.","example":"org_01HABCDEF","type":"string"},"workos_user_id":{"description":"WorkOS user id used to resolve bearer tokens into local users.","example":"user_01HABCDEF","type":"string"}},"required":["id","created_at","updated_at","workos_user_id"],"type":"object"},"UserHistory":{"description":"Audit history for User rows, used for incident investigation.","properties":{"created_at":{"description":"Row creation timestamp.","example":"2026-06-04T20:38:00Z","format":"date-time","type":"string"},"email":{"description":"Best-known WorkOS primary email for the user.","example":"user@example.com","type":"string"},"history_time":{"description":"Timestamp when this history record was written.","example":"2026-06-04T20:40:00Z","format":"date-time","type":"string"},"id":{"description":"Stable UUID primary key.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"operation":{"description":"Mutation operation that produced this history row.","enum":["INSERT","UPDATE","DELETE"],"example":"UPDATE","type":"string"},"ref":{"description":"UUID of the source row represented by a history row.","example":"123e4567-e89b-12d3-a456-426614174000","format":"uuid","type":"string"},"updated_at":{"description":"Last row update timestamp.","example":"2026-06-04T20:39:00Z","format":"date-time","type":"string"},"workos_org_id":{"description":"Optional WorkOS organization id for B2B/workspace contexts.","example":"org_01HABCDEF","type":"string"},"workos_user_id":{"description":"WorkOS user id used to resolve bearer tokens into local users.","example":"user_01HABCDEF","type":"string"}},"required":["id","created_at","updated_at","history_time","operation","workos_user_id"],"type":"object"},"VoiceTextToSpeechRequest":{"description":"ElevenLabs text-to-speech request body. Solomon AI API reads text for credit charging and forwards the full JSON body unchanged.","properties":{"model_id":{"description":"Optional ElevenLabs model id.","example":"eleven_multilingual_v2","nullable":true,"type":"string"},"text":{"description":"Text to synthesize. Charged per Unicode character.","example":"Hello from Solomon AI.","type":"string"},"voice_settings":{"description":"Optional ElevenLabs voice settings forwarded unchanged.","properties":{"similarity_boost":{"description":"Voice similarity boost.","example":0.75,"type":"number"},"stability":{"description":"Voice stability.","example":0.5,"type":"number"},"style":{"description":"Style exaggeration.","example":0,"type":"number"},"use_speaker_boost":{"description":"Speaker boost toggle.","example":true,"type":"boolean"}},"type":"object"}},"required":["text"],"type":"object"},"WorkOSExchangeRequest":{"description":"Authorization-code exchange request sent by the desktop after AuthKit redirects back.","properties":{"code":{"description":"Authorization code returned by WorkOS AuthKit.","example":"auth_code_123","type":"string"},"codeVerifier":{"description":"PKCE verifier matching the original code challenge. Optional when PKCE was not used.","example":"pkce-verifier","nullable":true,"type":"string"}},"required":["code"],"type":"object"},"WorkOSLoginURLResponse":{"description":"AuthKit authorize URL for the desktop to open in a browser.","properties":{"url":{"description":"Fully-qualified WorkOS AuthKit authorize URL with PKCE and state query parameters.","example":"http://localhost:18090/user_management/authorize?client_id=solomon-desktop-kind&response_type=code&state=abc","type":"string"}},"required":["url"],"type":"object"},"WorkOSRefreshRequest":{"description":"Refresh request for a WorkOS AuthKit token bundle.","properties":{"refreshToken":{"description":"Refresh token previously returned by the WorkOS broker.","example":"refresh_token_123","type":"string"}},"required":["refreshToken"],"type":"object"},"WorkOSTokenBundle":{"description":"Desktop-facing token bundle normalized from WorkOS authenticate responses.","properties":{"access_token":{"description":"JWT access token used as Authorization: Bearer for authenticated Solomon AI API calls.","example":"example-access-token","type":"string"},"email":{"description":"Best-known WorkOS primary email for the user.","example":"user@example.com","nullable":true,"type":"string"},"expires_at":{"description":"Credential or one-time ticket expiry timestamp.","example":"2026-06-04T20:48:00Z","format":"int64","type":"integer"},"refresh_token":{"description":"Refresh token for obtaining a new WorkOS access token.","example":"refresh_token_123","nullable":true,"type":"string"},"token_type":{"description":"Token type.","enum":["Bearer"],"example":"Bearer","type":"string"},"user_id":{"description":"WorkOS user id when available.","example":"user_01HABCDEF","nullable":true,"type":"string"}},"required":["access_token","expires_at","token_type"],"type":"object"}},"securitySchemes":{"BearerAuth":{"bearerFormat":"JWT","description":"WorkOS/OIDC access token. Authenticated desktop calls send this as Authorization: Bearer <token>.","scheme":"bearer","type":"http"},"HookHMAC":{"description":"HMAC-SHA256 over the raw request body, formatted as sha256=<hex>.","in":"header","name":"X-Hook-Signature","type":"apiKey"},"InternalSecret":{"description":"Static shared secret for server-to-server internal APIs.","in":"header","name":"X-Internal-Secret","type":"apiKey"},"WebhookHMAC":{"description":"HMAC-SHA256 over <X-Webhook-Timestamp>.<raw request body>, formatted as sha256=<hex>. The Unix timestamp must be within five minutes of the server clock.","in":"header","name":"X-Webhook-Signature","type":"apiKey"}}},"externalDocs":{"description":"Local kind deployment workflow","url":"https://github.com/Oppulence-Engineering/rowboat/blob/main/docs/LOCAL_KIND_ROWBOAT_API.md"},"info":{"description":"Rowboat's API brokers WorkOS sign-in, billing and credit state, OpenAI-compatible LLM calls, vendor proxies, Google OAuth handoff, connector OAuth, Composio proxying, internal webhooks, and admin GraphQL. The documented paths below are the routes mounted by cmd/server/wire.go.","title":"Oppulence API","version":"0.1.0"},"openapi":"3.0.3","paths":{"/graphql":{"post":{"description":"Internal admin GraphQL endpoint over the ent graph. The internal-secret middleware marks the request internal so resolvers can bypass per-user tenant scoping.","operationId":"graphql","requestBody":{"content":{"application/json":{"example":{"query":"{ users(first: 10) { edges { node { id email } } } }"},"schema":{"$ref":"#/components/schemas/GraphQLRequest"}}},"description":"GraphQL request body.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"data":{"users":{"edges":[]}}},"schema":{"$ref":"#/components/schemas/GraphQLResponse"}}},"description":"GraphQL response."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"InternalSecret":[]}],"summary":"Admin GraphQL","tags":["GraphQL"]}},"/healthz":{"get":{"description":"Returns ok when the HTTP process is alive. This does not prove dependencies are reachable.","operationId":"getHealthz","responses":{"200":{"content":{"application/json":{"example":{"status":"ok"},"schema":{"$ref":"#/components/schemas/HealthResponse"}}},"description":"Process is alive."}},"summary":"Liveness probe","tags":["System"]}},"/oauth-hooks/pre-consent":{"post":{"description":"Shared-secret webhook called by OAuth infrastructure before consent. It resolves the requested connector and returns allow=true or an upsell payload based on the user's billing plan.","operationId":"preConsent","requestBody":{"content":{"application/json":{"example":{"connector":"canvas","requested_audience":"canvas-api","workos_user_id":"user_01HABCDEF"},"schema":{"$ref":"#/components/schemas/PreConsentRequest"}}},"description":"Pre-consent webhook payload.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"allow":false,"upsell":{"message":"Upgrade to pro to connect Canvas","requiredPlan":"pro"}},"schema":{"$ref":"#/components/schemas/PreConsentResponse"}}},"description":"Consent decision."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"HookHMAC":[]}],"summary":"Evaluate connector pre-consent entitlement","tags":["Webhooks"]}},"/oauth/google/callback":{"get":{"description":"Google redirect target. Exchanges the authorization code server-side using the sealed PKCE verifier, parks the token bundle under the provider-bound state ticket, and returns an HTML page that deep-links back to the desktop.","operationId":"handleGoogleOAuthCallback","parameters":[{"description":"Opaque user-bound state ticket minted by /v1/google-oauth/start.","in":"query","name":"state","required":true,"schema":{"description":"State ticket.","example":"state_abc123","type":"string"}},{"description":"Authorization code returned by Google.","in":"query","name":"code","required":false,"schema":{"description":"Authorization code.","example":"4/0AfJoh...","type":"string"}},{"description":"OAuth error returned by Google when the user cancels or consent fails.","in":"query","name":"error","required":false,"schema":{"description":"OAuth error.","example":"access_denied","type":"string"}}],"responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"HTML page that redirects to solomon-ai://oauth/google/done."},"400":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"HTML error page for missing or expired state/code."}},"summary":"Handle Google OAuth callback","tags":["Google OAuth"]}},"/oauth/slack/callback":{"get":{"description":"Slack redirect target. Exchanges the authorization code server-side, parks the sealed workspace bundle under the state ticket, and returns an HTML page that deep-links back to the desktop.","operationId":"handleSlackOAuthCallback","parameters":[{"description":"Opaque user-bound state ticket minted by /v1/slack-oauth/start.","in":"query","name":"state","required":true,"schema":{"description":"State ticket.","example":"state_abc123","type":"string"}},{"description":"Authorization code returned by Slack.","in":"query","name":"code","required":false,"schema":{"description":"Authorization code.","example":"1234.5678.abcd","type":"string"}},{"description":"OAuth error returned by Slack when the user cancels the install.","in":"query","name":"error","required":false,"schema":{"description":"OAuth error.","example":"access_denied","type":"string"}}],"responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"HTML page that redirects to solomon-ai://oauth/slack/done."},"400":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"HTML error page for missing or expired state/code."}},"summary":"Handle Slack OAuth callback","tags":["Slack OAuth"]}},"/openapi.json":{"get":{"description":"Returns this enriched OpenAPI document. Scalar uses this endpoint to render /docs.","operationId":"getOpenAPI","responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"OpenAPI document.","type":"object"}}},"description":"OpenAPI 3.0 JSON document."}},"summary":"Download OpenAPI document","tags":["System"]}},"/readyz":{"get":{"description":"Runs registered readiness checks such as database connectivity and returns ready only when dependencies are usable.","operationId":"getReadyz","responses":{"200":{"content":{"application/json":{"example":{"status":"ready"},"schema":{"$ref":"#/components/schemas/ReadyResponse"}}},"description":"Service is ready."},"503":{"$ref":"#/components/responses/503"}},"summary":"Readiness probe","tags":["System"]}},"/v1/auth/workos/exchange":{"post":{"description":"Completes the authorization-code exchange server-side with the WorkOS API key, then returns the desktop token bundle.","operationId":"exchangeWorkOSToken","requestBody":{"content":{"application/json":{"example":{"code":"auth_code_123","codeVerifier":"pkce-verifier"},"schema":{"$ref":"#/components/schemas/WorkOSExchangeRequest"}}},"description":"Authorization code and optional PKCE verifier.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"access_token":"example-access-token","email":"user@example.com","expires_at":1790784000,"refresh_token":"example-refresh-token","token_type":"Bearer","user_id":"user_01HABCDEF"},"schema":{"$ref":"#/components/schemas/WorkOSTokenBundle"}}},"description":"WorkOS token bundle."},"400":{"$ref":"#/components/responses/400"},"409":{"$ref":"#/components/responses/409"},"502":{"$ref":"#/components/responses/502"}},"summary":"Exchange WorkOS authorization code","tags":["Auth"]}},"/v1/auth/workos/login-url":{"get":{"description":"Builds the WorkOS AuthKit authorize URL for the desktop. The desktop opens the returned URL in the browser, preserving state and optional PKCE challenge.","operationId":"createWorkOSLoginURL","parameters":[{"description":"Desktop loopback or custom redirect URI registered with the provider.","in":"query","name":"redirect_uri","required":true,"schema":{"description":"Redirect URI.","example":"http://localhost:8080/oauth/callback","type":"string"}},{"description":"Opaque state generated by the desktop and echoed through the login flow.","in":"query","name":"state","required":true,"schema":{"description":"OAuth state.","example":"kind-smoke","type":"string"}},{"description":"Optional S256 PKCE code challenge.","in":"query","name":"code_challenge","required":false,"schema":{"description":"PKCE challenge.","example":"kind-smoke-challenge","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"url":"http://localhost:18090/user_management/authorize?client_id=solomon-desktop-kind&response_type=code&state=kind-smoke"},"schema":{"$ref":"#/components/schemas/WorkOSLoginURLResponse"}}},"description":"Authorize URL."},"400":{"$ref":"#/components/responses/400"},"502":{"$ref":"#/components/responses/502"}},"summary":"Create WorkOS AuthKit login URL","tags":["Auth"]}},"/v1/auth/workos/refresh":{"post":{"description":"Refreshes a WorkOS AuthKit access token using the server-held WorkOS API key.","operationId":"refreshWorkOSToken","requestBody":{"content":{"application/json":{"example":{"refreshToken":"refresh_token_123"},"schema":{"$ref":"#/components/schemas/WorkOSRefreshRequest"}}},"description":"Refresh token payload.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"access_token":"example-access-token","email":"user@example.com","expires_at":1790784000,"refresh_token":"example-refresh-token","token_type":"Bearer","user_id":"user_01HABCDEF"},"schema":{"$ref":"#/components/schemas/WorkOSTokenBundle"}}},"description":"Refreshed WorkOS token bundle."},"400":{"$ref":"#/components/responses/400"},"409":{"$ref":"#/components/responses/409"},"502":{"$ref":"#/components/responses/502"}},"summary":"Refresh WorkOS token bundle","tags":["Auth"]}},"/v1/background-task-runs":{"get":{"description":"Lists all background task runs visible to the authenticated user. Use this for dashboards and polling views that need queued, running, failed, or API-worker Temporal runs without knowing a task slug first.","operationId":"listBackgroundTaskRunsForAccount","parameters":[{"description":"Optional run status filter. Use queued for desktop pickup or running/failed/succeeded for polling dashboards.","in":"query","name":"status","required":false,"schema":{"description":"Run status.","enum":["queued","running","succeeded","failed","stopped"],"example":"queued","type":"string"}},{"description":"Optional execution backend filter.","in":"query","name":"executor","required":false,"schema":{"description":"Run executor.","enum":["desktop","api"],"example":"api","type":"string"}},{"description":"Maximum runs to return, from 1 to 500. Defaults to 100.","in":"query","name":"limit","required":false,"schema":{"description":"Page size.","example":100,"type":"integer"}},{"description":"RFC3339 cursor returned as nextCursor from a previous page.","in":"query","name":"cursor","required":false,"schema":{"description":"Pagination cursor.","example":"2026-06-04T21:00:30Z","format":"date-time","type":"string"}},{"description":"Optional task slug filter for account-wide run polling.","in":"query","name":"slug","required":false,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"runs":[{"completedAt":"2026-06-04T21:02:00Z","createdAt":"2026-06-04T21:00:30Z","error":"","executor":"desktop","id":"77f5e632-a841-4557-a8e4-9b8f0d207ff4","localRunId":"local-run-42","model":"openai/gpt-4.1-mini","previousRunId":"","progressMessage":"Completed.","progressPercent":100,"provider":"openai","revision":2,"runId":"run-20260604-210000","slug":"daily-summary","startedAt":"2026-06-04T21:01:00Z","status":"succeeded","subUseCase":"daily-summary","summary":"No high-priority account changes.","trigger":"manual","updatedAt":"2026-06-04T21:02:05Z","useCase":"background-task"}]},"schema":{"$ref":"#/components/schemas/BackgroundTaskRunsResponse"}}},"description":"Account run list."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"List account background task runs","tags":["Background Tasks"]}},"/v1/background-task-templates":{"get":{"description":"Lists built-in API-target task templates that can be instantiated into normal background tasks. Templates provide known-good instructions, triggers, and execution defaults for common cloud task patterns.","operationId":"listBackgroundTaskTemplates","responses":{"200":{"content":{"application/json":{"example":{"templates":[{"active":true,"description":"Summarize new priority email and produce a short follow-up plan.","executionTarget":"api","instructions":"Review recent important Gmail messages and produce a markdown digest.","model":"anthropic/claude-sonnet-4-5","name":"Inbox Digest","provider":"openrouter","requiredConnectors":["google"],"slug":"inbox-digest","tags":["gmail","digest","scheduled"],"taskSlug":"inbox-digest","triggers":{"cronExpr":"0 8 * * 1-5","timezone":"America/New_York"}}]},"schema":{"$ref":"#/components/schemas/BackgroundTaskTemplatesResponse"}}},"description":"Task templates."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"List background task templates","tags":["Background Tasks"]}},"/v1/background-task-templates/{templateSlug}":{"get":{"description":"Fetches one built-in task template by slug so clients can preview the instructions, default trigger, and required connectors before instantiation.","operationId":"getBackgroundTaskTemplate","parameters":[{"description":"Background task template slug.","in":"path","name":"templateSlug","required":true,"schema":{"description":"Template slug.","example":"inbox-digest","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"active":true,"description":"Summarize new priority email and produce a short follow-up plan.","executionTarget":"api","instructions":"Review recent important Gmail messages and produce a markdown digest.","model":"anthropic/claude-sonnet-4-5","name":"Inbox Digest","provider":"openrouter","requiredConnectors":["google"],"slug":"inbox-digest","tags":["gmail","digest","scheduled"],"taskSlug":"inbox-digest","triggers":{"cronExpr":"0 8 * * 1-5","timezone":"America/New_York"}},"schema":{"$ref":"#/components/schemas/BackgroundTaskTemplate"}}},"description":"Task template."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Get background task template","tags":["Background Tasks"]}},"/v1/background-task-templates/{templateSlug}/instantiate":{"post":{"description":"Creates a normal background task from a built-in template. The resulting task is owned by the authenticated user and then follows the same trigger, admission, and Temporal execution path as tasks created directly.","operationId":"instantiateBackgroundTaskTemplate","parameters":[{"description":"Background task template slug.","in":"path","name":"templateSlug","required":true,"schema":{"description":"Template slug.","example":"inbox-digest","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"name":"Executive Inbox Digest","slug":"exec-inbox"},"schema":{"$ref":"#/components/schemas/BackgroundTaskTemplateInstantiateRequest"}}},"description":"Optional template overrides.","required":false},"responses":{"201":{"content":{"application/json":{"example":{"active":true,"createdAt":"2026-06-04T20:38:00Z","executionTarget":"desktop","id":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5","instructions":"Summarize important account changes and draft follow-up notes.","lastAttemptAt":"2026-06-04T21:00:00Z","lastRunAt":"2026-06-04T21:02:00Z","lastRunError":"","lastRunId":"run-20260604-210000","lastRunSummary":"No high-priority account changes.","model":"openai/gpt-4.1-mini","name":"Daily Account Summary","provider":"openai","revision":2,"slug":"daily-summary","triggers":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"updatedAt":"2026-06-04T20:39:00Z"},"schema":{"$ref":"#/components/schemas/BackgroundTask"}}},"description":"Created task."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"example":{"code":"conflict","detail":"background task already exists","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/conflict"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A task with this slug already exists for the user."},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Instantiate background task template","tags":["Background Tasks"]}},"/v1/background-tasks":{"get":{"description":"Lists the authenticated user's server-readable desktop background task mirrors ordered by slug. This is the primary sync pull for the desktop task registry.","operationId":"listBackgroundTasks","responses":{"200":{"content":{"application/json":{"example":{"tasks":[{"active":true,"createdAt":"2026-06-04T20:38:00Z","executionTarget":"desktop","id":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5","instructions":"Summarize important account changes and draft follow-up notes.","lastAttemptAt":"2026-06-04T21:00:00Z","lastRunAt":"2026-06-04T21:02:00Z","lastRunError":"","lastRunId":"run-20260604-210000","lastRunSummary":"No high-priority account changes.","model":"openai/gpt-4.1-mini","name":"Daily Account Summary","provider":"openai","revision":2,"slug":"daily-summary","triggers":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"updatedAt":"2026-06-04T20:39:00Z"}]},"schema":{"$ref":"#/components/schemas/BackgroundTaskListResponse"}}},"description":"Task list."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"List background tasks","tags":["Background Tasks"]},"post":{"description":"Creates the cloud mirror for a desktop task.yaml entry. If slug is omitted, Solomon AI API derives one from name. Slugs are unique per authenticated user.","operationId":"createBackgroundTask","requestBody":{"content":{"application/json":{"example":{"active":true,"createdAt":"2026-06-04T20:38:00Z","instructions":"Summarize important account changes and draft follow-up notes.","model":"openai/gpt-4.1-mini","name":"Daily Account Summary","provider":"openai","slug":"daily-summary","triggers":{"cronExpr":"0 9 * * *","timezone":"America/New_York"}},"schema":{"$ref":"#/components/schemas/BackgroundTaskCreateRequest"}}},"description":"Task mirror payload.","required":true},"responses":{"201":{"content":{"application/json":{"example":{"active":true,"createdAt":"2026-06-04T20:38:00Z","executionTarget":"desktop","id":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5","instructions":"Summarize important account changes and draft follow-up notes.","lastAttemptAt":"2026-06-04T21:00:00Z","lastRunAt":"2026-06-04T21:02:00Z","lastRunError":"","lastRunId":"run-20260604-210000","lastRunSummary":"No high-priority account changes.","model":"openai/gpt-4.1-mini","name":"Daily Account Summary","provider":"openai","revision":2,"slug":"daily-summary","triggers":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"updatedAt":"2026-06-04T20:39:00Z"},"schema":{"$ref":"#/components/schemas/BackgroundTask"}}},"description":"Created task mirror."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"409":{"content":{"application/problem+json":{"example":{"code":"conflict","detail":"background task already exists","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/conflict"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A task with this slug already exists for the user."},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Create background task mirror","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}":{"delete":{"description":"Deletes the task mirror and its artifact, runs, and run events after verifying the supplied task revision. This supports full local lifecycle parity when a desktop task is removed.","operationId":"deleteBackgroundTask","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Current task revision required for delete.","in":"query","name":"revision","required":true,"schema":{"description":"Task revision.","example":2,"type":"integer"}}],"responses":{"204":{"description":"Task mirror and child rows deleted."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"example":{"code":"conflict","currentRevision":3,"detail":"revision conflict","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/conflict"},"schema":{"$ref":"#/components/schemas/RevisionConflictEnvelope"}}},"description":"Revision conflict. The caller wrote with a stale revision and should retry with currentRevision."},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Delete background task mirror","tags":["Background Tasks"]},"get":{"description":"Fetches one task mirror by slug for the authenticated user. Tenant scoping ensures the same slug can exist for different users without leaking data.","operationId":"getBackgroundTask","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"active":true,"createdAt":"2026-06-04T20:38:00Z","executionTarget":"desktop","id":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5","instructions":"Summarize important account changes and draft follow-up notes.","lastAttemptAt":"2026-06-04T21:00:00Z","lastRunAt":"2026-06-04T21:02:00Z","lastRunError":"","lastRunId":"run-20260604-210000","lastRunSummary":"No high-priority account changes.","model":"openai/gpt-4.1-mini","name":"Daily Account Summary","provider":"openai","revision":2,"slug":"daily-summary","triggers":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"updatedAt":"2026-06-04T20:39:00Z"},"schema":{"$ref":"#/components/schemas/BackgroundTask"}}},"description":"Task mirror."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Get background task mirror","tags":["Background Tasks"]},"patch":{"description":"Applies a partial task update using optimistic locking. The desktop should send the current revision from its last read; stale writes return currentRevision for merge/retry.","operationId":"patchBackgroundTask","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"lastRunAt":"2026-06-04T21:02:00Z","lastRunSummary":"No high-priority account changes.","name":"Daily Account Summary","revision":2,"triggers":null},"schema":{"$ref":"#/components/schemas/BackgroundTaskPatchRequest"}}},"description":"Revision-checked task patch.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"active":true,"createdAt":"2026-06-04T20:38:00Z","executionTarget":"desktop","id":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5","instructions":"Summarize important account changes and draft follow-up notes.","lastAttemptAt":"2026-06-04T21:00:00Z","lastRunAt":"2026-06-04T21:02:00Z","lastRunError":"","lastRunId":"run-20260604-210000","lastRunSummary":"No high-priority account changes.","model":"openai/gpt-4.1-mini","name":"Daily Account Summary","provider":"openai","revision":2,"slug":"daily-summary","triggers":{"cronExpr":"0 9 * * *","timezone":"America/New_York"},"updatedAt":"2026-06-04T20:39:00Z"},"schema":{"$ref":"#/components/schemas/BackgroundTask"}}},"description":"Updated task mirror."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"example":{"code":"conflict","currentRevision":3,"detail":"revision conflict","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/conflict"},"schema":{"$ref":"#/components/schemas/RevisionConflictEnvelope"}}},"description":"Revision conflict. The caller wrote with a stale revision and should retry with currentRevision."},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Patch background task mirror","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/artifact":{"get":{"description":"Returns the markdown artifact mirrored from bg-tasks/<slug>/index.md. If no artifact exists yet, the API returns an empty body with revision 0 so the desktop can create it with PUT.","operationId":"getBackgroundTaskArtifact","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"body":"# Daily Account Summary\n\nUse this context when summarizing account changes.","revision":2,"slug":"daily-summary","updatedAt":"2026-06-04T20:39:00Z"},"schema":{"$ref":"#/components/schemas/BackgroundTaskArtifact"}}},"description":"Task artifact."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Get task artifact","tags":["Background Tasks"]},"put":{"description":"Creates or updates the markdown artifact mirror. Updates require the current artifact revision; creation can omit revision or send revision 0.","operationId":"putBackgroundTaskArtifact","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"body":"# Daily Account Summary\n\nUpdated context.","revision":2},"schema":{"$ref":"#/components/schemas/BackgroundTaskArtifactPutRequest"}}},"description":"Artifact body and optional revision.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"body":"# Daily Account Summary\n\nUse this context when summarizing account changes.","revision":2,"slug":"daily-summary","updatedAt":"2026-06-04T20:39:00Z"},"schema":{"$ref":"#/components/schemas/BackgroundTaskArtifact"}}},"description":"Saved task artifact."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"example":{"code":"conflict","currentRevision":3,"detail":"revision conflict","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/conflict"},"schema":{"$ref":"#/components/schemas/RevisionConflictEnvelope"}}},"description":"Revision conflict. The caller wrote with a stale revision and should retry with currentRevision."},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Put task artifact","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/runs":{"get":{"description":"Lists mirrored runs for a task. Poll with status, executor, limit, and cursor filters to drive desktop queue pickup, dashboards, and API-worker Temporal status views.","operationId":"listBackgroundTaskRuns","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Optional run status filter. Use queued for desktop pickup or running/failed/succeeded for polling dashboards.","in":"query","name":"status","required":false,"schema":{"description":"Run status.","enum":["queued","running","succeeded","failed","stopped"],"example":"queued","type":"string"}},{"description":"Optional execution backend filter.","in":"query","name":"executor","required":false,"schema":{"description":"Run executor.","enum":["desktop","api"],"example":"api","type":"string"}},{"description":"Maximum runs to return, from 1 to 500. Defaults to 100.","in":"query","name":"limit","required":false,"schema":{"description":"Page size.","example":100,"type":"integer"}},{"description":"RFC3339 cursor returned as nextCursor from a previous page.","in":"query","name":"cursor","required":false,"schema":{"description":"Pagination cursor.","example":"2026-06-04T21:00:30Z","format":"date-time","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"runs":[{"completedAt":"2026-06-04T21:02:00Z","createdAt":"2026-06-04T21:00:30Z","error":"","executor":"desktop","id":"77f5e632-a841-4557-a8e4-9b8f0d207ff4","localRunId":"local-run-42","model":"openai/gpt-4.1-mini","previousRunId":"","progressMessage":"Completed.","progressPercent":100,"provider":"openai","revision":2,"runId":"run-20260604-210000","slug":"daily-summary","startedAt":"2026-06-04T21:01:00Z","status":"succeeded","subUseCase":"daily-summary","summary":"No high-priority account changes.","trigger":"manual","updatedAt":"2026-06-04T21:02:05Z","useCase":"background-task"}]},"schema":{"$ref":"#/components/schemas/BackgroundTaskRunsResponse"}}},"description":"Task runs."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"List task runs","tags":["Background Tasks"]},"post":{"description":"Creates a run mirror for a desktop execution. Use this for local scheduler/manual runs; use /trigger when a remote user action should queue a new local execution.","operationId":"createBackgroundTaskRun","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"model":"openai/gpt-4.1-mini","provider":"openai","runId":"run-20260604-210000","startedAt":"2026-06-04T21:01:00Z","status":"running","subUseCase":"daily-summary","trigger":"manual","useCase":"background-task"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRunCreateRequest"}}},"description":"Run mirror payload.","required":true},"responses":{"201":{"content":{"application/json":{"example":{"completedAt":"2026-06-04T21:02:00Z","createdAt":"2026-06-04T21:00:30Z","error":"","executor":"desktop","id":"77f5e632-a841-4557-a8e4-9b8f0d207ff4","localRunId":"local-run-42","model":"openai/gpt-4.1-mini","previousRunId":"","progressMessage":"Completed.","progressPercent":100,"provider":"openai","revision":2,"runId":"run-20260604-210000","slug":"daily-summary","startedAt":"2026-06-04T21:01:00Z","status":"succeeded","subUseCase":"daily-summary","summary":"No high-priority account changes.","trigger":"manual","updatedAt":"2026-06-04T21:02:05Z","useCase":"background-task"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRun"}}},"description":"Created run mirror."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"example":{"code":"conflict","detail":"run already exists","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/conflict"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A run with this runId already exists for the user."},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Create task run mirror","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/runs/{runId}":{"get":{"description":"Fetches the full mirrored state for one desktop or API-worker run, including Temporal ids and polling progress when present.","operationId":"getBackgroundTaskRun","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Cloud-visible run id for a background task run.","in":"path","name":"runId","required":true,"schema":{"description":"Run id.","example":"run-20260604-210000","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"completedAt":"2026-06-04T21:02:00Z","createdAt":"2026-06-04T21:00:30Z","error":"","executor":"desktop","id":"77f5e632-a841-4557-a8e4-9b8f0d207ff4","localRunId":"local-run-42","model":"openai/gpt-4.1-mini","previousRunId":"","progressMessage":"Completed.","progressPercent":100,"provider":"openai","revision":2,"runId":"run-20260604-210000","slug":"daily-summary","startedAt":"2026-06-04T21:01:00Z","status":"succeeded","subUseCase":"daily-summary","summary":"No high-priority account changes.","trigger":"manual","updatedAt":"2026-06-04T21:02:05Z","useCase":"background-task"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRun"}}},"description":"Run mirror."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Get task run","tags":["Background Tasks"]},"patch":{"description":"Updates run state with optimistic locking. Desktop should patch queued remote-trigger runs to running/succeeded/failed as it claims and completes them locally.","operationId":"patchBackgroundTaskRun","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Cloud-visible run id for a background task run.","in":"path","name":"runId","required":true,"schema":{"description":"Run id.","example":"run-20260604-210000","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"completedAt":"2026-06-04T21:02:00Z","localRunId":"local-run-42","revision":1,"status":"succeeded","summary":"No high-priority account changes."},"schema":{"$ref":"#/components/schemas/BackgroundTaskRunPatchRequest"}}},"description":"Revision-checked run patch.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"completedAt":"2026-06-04T21:02:00Z","createdAt":"2026-06-04T21:00:30Z","error":"","executor":"desktop","id":"77f5e632-a841-4557-a8e4-9b8f0d207ff4","localRunId":"local-run-42","model":"openai/gpt-4.1-mini","previousRunId":"","progressMessage":"Completed.","progressPercent":100,"provider":"openai","revision":2,"runId":"run-20260604-210000","slug":"daily-summary","startedAt":"2026-06-04T21:01:00Z","status":"succeeded","subUseCase":"daily-summary","summary":"No high-priority account changes.","trigger":"manual","updatedAt":"2026-06-04T21:02:05Z","useCase":"background-task"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRun"}}},"description":"Updated run mirror."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"example":{"code":"conflict","currentRevision":3,"detail":"revision conflict","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/conflict"},"schema":{"$ref":"#/components/schemas/RevisionConflictEnvelope"}}},"description":"Revision conflict. The caller wrote with a stale revision and should retry with currentRevision."},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Patch task run mirror","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/runs/{runId}/cancel":{"post":{"description":"Requests Temporal cancellation for an API-worker run and mirrors stopped/canceled state to Solomon AI. Desktop-local runs are rejected unless a future desktop cancellation bridge is added.","operationId":"cancelBackgroundTaskRun","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Cloud-visible run id for a background task run.","in":"path","name":"runId","required":true,"schema":{"description":"Run id.","example":"run-20260604-210000","type":"string"}}],"responses":{"202":{"content":{"application/json":{"example":{"completedAt":null,"createdAt":"2026-06-04T21:00:30Z","error":"","executor":"desktop","id":"77f5e632-a841-4557-a8e4-9b8f0d207ff4","localRunId":"","model":"openai/gpt-4.1-mini","previousRunId":"","progressMessage":"Completed.","progressPercent":100,"provider":"openai","requestedContext":"Run this now and focus on high-risk accounts.","revision":1,"runId":"remote-trigger-4a31958c-3a0a-4cb2-9361-ea563cd0477b","slug":"daily-summary","startedAt":null,"status":"queued","subUseCase":"daily-summary","summary":"","trigger":"manual","updatedAt":"2026-06-04T21:02:05Z","useCase":"background-task"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRun"}}},"description":"Cancellation accepted."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Cancel API-worker run","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/runs/{runId}/events":{"get":{"description":"Returns durable log/progress events for a run ordered by seq. Use afterSeq for incremental polling of desktop and API-worker progress events.","operationId":"listBackgroundTaskRunEvents","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Cloud-visible run id for a background task run.","in":"path","name":"runId","required":true,"schema":{"description":"Run id.","example":"run-20260604-210000","type":"string"}},{"description":"Optional sequence cursor. When provided, only events with seq greater than this value are returned.","in":"query","name":"afterSeq","required":false,"schema":{"description":"Last seen event seq.","example":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"example":{"events":[{"event":{"summary":"ok","type":"temporal.completed"},"id":"06227adb-924f-46f1-b324-1b10d080a660","receivedAt":"2026-06-04T21:02:05Z","seq":1,"type":"temporal.completed"}]},"schema":{"$ref":"#/components/schemas/BackgroundTaskRunEventsResponse"}}},"description":"Run log/progress events."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"List task run logs","tags":["Background Tasks"]},"post":{"description":"Appends a batch of durable log/progress events. The unique (run, seq) key makes retries idempotent: duplicate seq values are counted as skipped.","operationId":"appendBackgroundTaskRunEvents","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Cloud-visible run id for a background task run.","in":"path","name":"runId","required":true,"schema":{"description":"Run id.","example":"run-20260604-210000","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"events":[{"event":{"type":"started"},"seq":0},{"event":{"summary":"ok","type":"temporal.completed"},"seq":1,"type":"temporal.completed"}]},"schema":{"$ref":"#/components/schemas/BackgroundTaskRunEventsAppendRequest"}}},"description":"Run event batch.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"skipped":0,"stored":2},"schema":{"$ref":"#/components/schemas/BackgroundTaskRunEventsAppendResponse"}}},"description":"Append counts."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Append task run logs","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/runs/{runId}/events/stream":{"get":{"description":"Streams durable task log/progress events as application/x-ndjson. The stream first backfills events with seq greater than afterSeq, then tails the run log until a terminal event or client disconnect.","operationId":"streamBackgroundTaskRunEvents","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Cloud-visible run id for a background task run.","in":"path","name":"runId","required":true,"schema":{"description":"Run id.","example":"run-20260604-210000","type":"string"}},{"description":"Optional reconnect cursor. When provided, only events with seq greater than this value are streamed.","in":"query","name":"afterSeq","required":false,"schema":{"description":"Last seen event seq.","example":0,"type":"integer"}}],"responses":{"200":{"content":{"application/x-ndjson":{"example":{"event":{"summary":"ok","type":"temporal.completed"},"id":"06227adb-924f-46f1-b324-1b10d080a660","receivedAt":"2026-06-04T21:02:05Z","seq":1,"type":"temporal.completed"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRunEvent"}}},"description":"NDJSON stream of BackgroundTaskRunEvent objects."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Stream task run progress","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/runs/{runId}/retry":{"post":{"description":"Creates a new API-worker run linked by previousRunId and starts a fresh Temporal workflow using the previous trigger/context.","operationId":"retryBackgroundTaskRun","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Cloud-visible run id for a background task run.","in":"path","name":"runId","required":true,"schema":{"description":"Run id.","example":"run-20260604-210000","type":"string"}}],"responses":{"202":{"content":{"application/json":{"example":{"completedAt":null,"createdAt":"2026-06-04T21:00:30Z","error":"","executor":"api","id":"77f5e632-a841-4557-a8e4-9b8f0d207ff4","localRunId":"","model":"openai/gpt-4.1-mini","previousRunId":"","progressMessage":"Queued for API worker.","progressPercent":0,"provider":"openai","revision":2,"runId":"api-trigger-4a31958c-3a0a-4cb2-9361-ea563cd0477b","slug":"daily-summary","startedAt":null,"status":"queued","subUseCase":"daily-summary","summary":"No high-priority account changes.","temporalRunId":"00000000-0000-0000-0000-000000000001","temporalStatus":"Started","temporalWorkflowId":"background-task/user/daily-summary/api-trigger-4a31958c-3a0a-4cb2-9361-ea563cd0477b","trigger":"manual","updatedAt":"2026-06-04T21:02:05Z","useCase":"background-task"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRun"}}},"description":"Retry run queued."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Retry API-worker run","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/runs/{runId}/signal":{"post":{"description":"Sends a constrained control signal to the Temporal workflow. API-worker runs persist the signal as a durable run event and honor pause, resume, and update_context at cooperative runtime checkpoints between model steps.","operationId":"signalBackgroundTaskRun","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Cloud-visible run id for a background task run.","in":"path","name":"runId","required":true,"schema":{"description":"Run id.","example":"run-20260604-210000","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"payload":{"reason":"operator requested"},"signal":"pause"},"schema":{"$ref":"#/components/schemas/BackgroundTaskSignalRequest"}}},"description":"Signal payload.","required":true},"responses":{"202":{"content":{"application/json":{"example":{"completedAt":null,"createdAt":"2026-06-04T21:00:30Z","error":"","executor":"api","id":"77f5e632-a841-4557-a8e4-9b8f0d207ff4","localRunId":"","model":"openai/gpt-4.1-mini","previousRunId":"","progressMessage":"Queued for API worker.","progressPercent":0,"provider":"openai","revision":2,"runId":"api-trigger-4a31958c-3a0a-4cb2-9361-ea563cd0477b","slug":"daily-summary","startedAt":null,"status":"queued","subUseCase":"daily-summary","summary":"No high-priority account changes.","temporalRunId":"00000000-0000-0000-0000-000000000001","temporalStatus":"Started","temporalWorkflowId":"background-task/user/daily-summary/api-trigger-4a31958c-3a0a-4cb2-9361-ea563cd0477b","trigger":"manual","updatedAt":"2026-06-04T21:02:05Z","useCase":"background-task"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRun"}}},"description":"Signal accepted."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Signal API-worker run","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/runs/{runId}/status":{"get":{"description":"Returns a compact polling payload for one run. Clients should poll this Solomon AI API endpoint rather than Temporal directly.","operationId":"getBackgroundTaskRunStatus","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}},{"description":"Cloud-visible run id for a background task run.","in":"path","name":"runId","required":true,"schema":{"description":"Run id.","example":"run-20260604-210000","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"completedAt":null,"error":"","executor":"api","lastHeartbeatAt":"2026-06-04T21:01:30Z","progressMessage":"Building API-native task artifact.","progressPercent":50,"revision":3,"runId":"api-trigger-4a31958c-3a0a-4cb2-9361-ea563cd0477b","slug":"daily-summary","startedAt":"2026-06-04T21:01:00Z","status":"running","temporalRunId":"00000000-0000-0000-0000-000000000001","temporalStatus":"Running","temporalWorkflowId":"background-task/user/daily-summary/api-trigger-4a31958c-3a0a-4cb2-9361-ea563cd0477b"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRunStatusResponse"}}},"description":"Compact run status."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Poll task run status","tags":["Background Tasks"]}},"/v1/background-tasks/{slug}/trigger":{"post":{"description":"For executionTarget=desktop, queues a remote trigger with status=queued for desktop pickup. For executionTarget=api, creates an API-worker run and starts a Temporal workflow, while clients poll Solomon AI run status endpoints.","operationId":"triggerBackgroundTask","parameters":[{"description":"Background task slug, matching bg-tasks/<slug> locally.","in":"path","name":"slug","required":true,"schema":{"description":"Task slug.","example":"daily-summary","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"context":"Run this now and focus on high-risk accounts.","trigger":"manual"},"schema":{"$ref":"#/components/schemas/BackgroundTaskTriggerRequest"}}},"description":"Optional trigger context.","required":false},"responses":{"202":{"content":{"application/json":{"example":{"completedAt":null,"createdAt":"2026-06-04T21:00:30Z","error":"","executor":"desktop","id":"77f5e632-a841-4557-a8e4-9b8f0d207ff4","localRunId":"","model":"openai/gpt-4.1-mini","previousRunId":"","progressMessage":"Completed.","progressPercent":100,"provider":"openai","requestedContext":"Run this now and focus on high-risk accounts.","revision":1,"runId":"remote-trigger-4a31958c-3a0a-4cb2-9361-ea563cd0477b","slug":"daily-summary","startedAt":null,"status":"queued","subUseCase":"daily-summary","summary":"","trigger":"manual","updatedAt":"2026-06-04T21:02:05Z","useCase":"background-task"},"schema":{"$ref":"#/components/schemas/BackgroundTaskRun"}}},"description":"Queued or started run mirror."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Queue or start task trigger","tags":["Background Tasks"]}},"/v1/config":{"get":{"description":"Public endpoint fetched by the desktop before sign-in. Values identify the app origin, OIDC issuer, optional WebSocket API, and static OAuth client id.","operationId":"getConfig","responses":{"200":{"content":{"application/json":{"example":{"appUrl":"http://localhost:18080","oauthClientId":"solomon-desktop-kind","oidcIssuerUrl":"http://localhost:18090","supabaseUrl":"http://localhost:18090","websocketApiUrl":""},"schema":{"$ref":"#/components/schemas/ConfigResponse"}}},"description":"Desktop bootstrap config."}},"summary":"Fetch desktop bootstrap config","tags":["System"]}},"/v1/connections/{name}":{"delete":{"description":"Idempotently disconnects a connector for the authenticated user. If a refresh token exists, rowboat-api attempts to revoke it at Ory before deleting the local connection.","operationId":"deleteConnection","parameters":[{"description":"Connector slug, for example canvas, corinthian, or wispr.","in":"path","name":"name","required":true,"schema":{"description":"Connector slug.","example":"canvas","type":"string"}}],"responses":{"204":{"description":"Connector disconnected or was already absent."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Disconnect connector","tags":["Connectors"]}},"/v1/connections/{name}/api-key":{"post":{"description":"Stores a vendor-issued API key for an api_key connector. The key is sealed at rest and later minted back only through the connector MCP token endpoint.","operationId":"setConnectionAPIKey","parameters":[{"description":"Connector slug, for example canvas, corinthian, or wispr.","in":"path","name":"name","required":true,"schema":{"description":"Connector slug.","example":"canvas","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"apiKey":"example-vendor-key"},"schema":{"$ref":"#/components/schemas/ConnectionAPIKeyRequest"}}},"description":"Connector API key.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"connected":true},"schema":{"$ref":"#/components/schemas/ConnectionConnectedResponse"}}},"description":"Connector connected."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Connect API-key connector","tags":["Connectors"]}},"/v1/connections/{name}/callback":{"get":{"description":"Browser redirect target from Ory. The user is resolved from the sealed pending ticket, not from a bearer token. On success or failure it redirects to the desktop deep link.","operationId":"handleConnectionCallback","parameters":[{"description":"Connector slug, for example canvas, corinthian, or wispr.","in":"path","name":"name","required":true,"schema":{"description":"Connector slug.","example":"canvas","type":"string"}},{"description":"Opaque connection state generated by /start.","in":"query","name":"state","required":true,"schema":{"description":"State.","example":"state_abc123","type":"string"}},{"description":"Authorization code from Ory.","in":"query","name":"code","required":false,"schema":{"description":"Authorization code.","example":"code_abc123","type":"string"}},{"description":"OAuth error from Ory.","in":"query","name":"error","required":false,"schema":{"description":"OAuth error.","example":"access_denied","type":"string"}}],"responses":{"302":{"description":"Redirect to solomon-ai://connection-complete with connector and status.","headers":{"Location":{"description":"Redirect target.","schema":{"format":"uri","type":"string"}}}},"400":{"$ref":"#/components/responses/400"},"500":{"$ref":"#/components/responses/500"}},"summary":"Handle connector OAuth callback","tags":["Connectors"]}},"/v1/connections/{name}/claim":{"post":{"description":"Redeems the connector grant parked by the browser callback. Persistence is bound to the authenticated user that started the flow.","operationId":"claimConnection","parameters":[{"description":"Connector slug, for example canvas, corinthian, or wispr.","in":"path","name":"name","required":true,"schema":{"description":"Connector slug.","example":"canvas","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"state":"state_abc123"},"schema":{"$ref":"#/components/schemas/ConnectionClaimRequest"}}},"description":"Connector claim ticket.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"connected":true},"schema":{"$ref":"#/components/schemas/ConnectionConnectedResponse"}}},"description":"Connector connected."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"},"410":{"$ref":"#/components/responses/410"},"500":{"$ref":"#/components/responses/500"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Claim connector OAuth flow","tags":["Connectors"]}},"/v1/connections/{name}/mcp-token":{"post":{"description":"Returns a short-lived MCP access token and target MCP URL for a connected connector. OAuth connectors refresh through Ory; api_key connectors return the sealed vendor key directly.","operationId":"createMCPToken","parameters":[{"description":"Connector slug, for example canvas, corinthian, or wispr.","in":"path","name":"name","required":true,"schema":{"description":"Connector slug.","example":"canvas","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"access_token":"mcp_access_token","expires_at":1790784000,"mcpUrl":"https://api.canvas.solomon-ai.co/v1/mcp","token_type":"Bearer"},"schema":{"$ref":"#/components/schemas/MCPTokenResponse"}}},"description":"MCP token and endpoint."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Mint connector MCP token","tags":["Connectors"]}},"/v1/connections/{name}/start":{"post":{"description":"Creates a sealed pending connection ticket, builds the Ory authorize URL with PKCE, and returns it for the desktop to open in a browser.","operationId":"startConnection","parameters":[{"description":"Connector slug, for example canvas, corinthian, or wispr.","in":"path","name":"name","required":true,"schema":{"description":"Connector slug.","example":"canvas","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"authorize_url":"https://oauth.solomon-ai.co/oauth2/auth?client_id=rowboat-api&state=..."},"schema":{"$ref":"#/components/schemas/ConnectionStartResponse"}}},"description":"Connector authorize URL."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Start connector OAuth flow","tags":["Connectors"]}},"/v1/connectors":{"get":{"description":"Returns the configured connector registry plus the authenticated user's connection state for each connector.","operationId":"listConnectors","responses":{"200":{"content":{"application/json":{"example":{"connectors":[{"authType":"oauth","connected":true,"connectedAt":"2026-06-04T20:38:00Z","description":"Banking, invoicing, dunning, transactions","displayName":"Canvas","mcpTools":[{"name":"customer.lookup","trustTier":"read"}],"mcpUrl":"https://api.canvas.solomon-ai.co/v1/mcp","name":"canvas","scopes":["invoices:read"],"templateBlocks":[{"category":"finance","description":"Look up invoices and customers.","id":"invoice-context","mcpTools":["invoice.lookup"],"requiredScopes":["invoices:read"],"title":"Invoice context","trustTier":"read"}]}]},"schema":{"$ref":"#/components/schemas/ConnectorsResponse"}}},"description":"Connector registry with connection state."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"List connectors","tags":["Connectors"]}},"/v1/events":{"get":{"description":"Lists the authenticated user's ingested events ordered by receivedAt descending. Payload is omitted from list responses; fetch the detail endpoint for it.","operationId":"listCloudEvents","parameters":[{"description":"Filter by event source.","in":"query","name":"source","required":false,"schema":{"description":"Source.","example":"gmail","type":"string"}},{"description":"Filter by routing status.","in":"query","name":"routingStatus","required":false,"schema":{"description":"Routing status.","example":"routed","type":"string"}},{"description":"Only events received at or after this RFC3339 time.","in":"query","name":"since","required":false,"schema":{"description":"RFC3339 lower bound.","example":"2026-06-06T00:00:00Z","type":"string"}},{"description":"Only events received at or before this RFC3339 time.","in":"query","name":"until","required":false,"schema":{"description":"RFC3339 upper bound.","example":"2026-06-07T00:00:00Z","type":"string"}},{"description":"Page size (1-500, default 100).","in":"query","name":"limit","required":false,"schema":{"description":"Page size.","example":100,"type":"integer"}},{"description":"Opaque cursor from a prior page's nextCursor.","in":"query","name":"cursor","required":false,"schema":{"description":"Pagination cursor.","example":"","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"events":[],"nextCursor":""},"schema":{"$ref":"#/components/schemas/CloudEventListResponse"}}},"description":"Event page."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"List cloud events","tags":["Cloud Events"]},"post":{"description":"Stores one normalized event idempotently on (user, source, dedupeKey) and enqueues async routing to matching API-target background tasks. Returns 202 for a fresh event and 200 with deduped=true for a replay.","operationId":"ingestCloudEvent","requestBody":{"content":{"application/json":{"example":{"dedupeKey":"gmail:msg:msg_123","eventType":"email.received","payload":{"messageId":"msg_123","provider":"gmail"},"source":"internal","subject":"Invoice #4821 dispute","text":"Acme disputed invoice #4821 for $18,000 due to a pricing mismatch."},"schema":{"$ref":"#/components/schemas/CloudEventIngestRequest"}}},"description":"Normalized event envelope.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"deduped":true,"eventId":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","matchedTaskCount":1,"routingStatus":"routed"},"schema":{"$ref":"#/components/schemas/CloudEventIngestResponse"}}},"description":"Duplicate dedupeKey: existing event returned, routing not re-run."},"202":{"content":{"application/json":{"example":{"deduped":false,"eventId":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","routingStatus":"pending"},"schema":{"$ref":"#/components/schemas/CloudEventIngestResponse"}}},"description":"Event stored, routing enqueued."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"413":{"content":{"application/problem+json":{"example":{"code":"payload_too_large","detail":"payload exceeds 262144 bytes","requestId":"req-abc123","status":413,"title":"Request Entity Too Large","type":"https://api.rowboat.dev/problems/payload_too_large"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payload exceeds the configured size cap."},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Ingest a cloud event","tags":["Cloud Events"]}},"/v1/events/{eventId}":{"get":{"description":"Returns one event including the decrypted payload and the routing decision summary.","operationId":"getCloudEvent","parameters":[{"description":"Cloud event id.","in":"path","name":"eventId","required":true,"schema":{"description":"Event id.","example":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"dedupeKey":"gmail:msg:msg_123","id":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","matchedTaskCount":1,"receivedAt":"2026-06-06T14:00:02Z","routingStatus":"routed","source":"internal"},"schema":{"$ref":"#/components/schemas/CloudEvent"}}},"description":"Event detail."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Get a cloud event","tags":["Cloud Events"]}},"/v1/events/{eventId}/runs":{"get":{"description":"Returns the trigger=event runs this event fired — the event-to-run audit link.","operationId":"listCloudEventRuns","parameters":[{"description":"Cloud event id.","in":"path","name":"eventId","required":true,"schema":{"description":"Event id.","example":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"runs":[{"createdAt":"2026-06-06T14:00:10Z","executor":"api","runId":"event-7e0a1f2b","status":"succeeded","taskSlug":"acme-ar-watch","trigger":"event"}]},"schema":{"$ref":"#/components/schemas/CloudEventRunsResponse"}}},"description":"Linked runs."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"List runs triggered by a cloud event","tags":["Cloud Events"]}},"/v1/google-oauth":{"delete":{"description":"Removes the user's Google connection and purges data derived from it (the RFC 031 cloud mail index; evidence quotes are retained as the user's own action history). Idempotent: returns 204 whether or not a connection existed. The user should also revoke the grant in their Google account.","operationId":"disconnectGoogle","responses":{"204":{"description":"Disconnected (idempotent)."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Disconnect Google","tags":["Google OAuth"]}},"/v1/google-oauth/claim":{"post":{"description":"Consumes a one-time Google OAuth session ticket, requires the authenticated user to match the user that started it, persists the refresh token when present, and returns the token bundle to the desktop.","operationId":"claimGoogleOAuth","requestBody":{"content":{"application/json":{"example":{"session":"state_abc123"},"schema":{"$ref":"#/components/schemas/GoogleClaimRequest"}}},"description":"Google OAuth session ticket.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"access_token":"example-access-token","expires_at":1790784000,"refresh_token":"example-refresh-token","scope":"openid email profile","token_type":"Bearer"},"schema":{"$ref":"#/components/schemas/OAuthTokenBundle"}}},"description":"Claimed Google token bundle."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"},"410":{"$ref":"#/components/responses/410"},"500":{"$ref":"#/components/responses/500"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Claim Google OAuth token bundle","tags":["Google OAuth"]}},"/v1/google-oauth/refresh":{"post":{"description":"Refreshes a Google access token using the server-held Google OAuth client id and secret. Google usually omits refresh_token on refresh; the desktop should preserve the old refresh token.","operationId":"refreshGoogleOAuth","requestBody":{"content":{"application/json":{"example":{"refreshToken":"1//refresh"},"schema":{"$ref":"#/components/schemas/GoogleRefreshRequest"}}},"description":"Google refresh token payload.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"access_token":"example-access-token","expires_at":1790784000,"scope":"openid email profile","token_type":"Bearer"},"schema":{"$ref":"#/components/schemas/OAuthTokenBundle"}}},"description":"Refreshed Google access token bundle."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"409":{"$ref":"#/components/responses/409"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Refresh Google access token","tags":["Google OAuth"]}},"/v1/google-oauth/start":{"post":{"description":"Creates a one-time state ticket bound to the authenticated Rowboat user and a PKCE S256 verifier, then returns the Google consent URL for the desktop to open.","operationId":"startGoogleOAuth","responses":{"200":{"content":{"application/json":{"example":{"authorizeUrl":"https://accounts.google.com/o/oauth2/v2/auth?..."},"schema":{"properties":{"authorizeUrl":{"format":"uri","type":"string"}},"required":["authorizeUrl"],"type":"object"}}},"description":"Bound Google authorization URL."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"}},"security":[{"BearerAuth":[]}],"summary":"Start Google OAuth consent","tags":["Google OAuth"]}},"/v1/hubspot/search":{"post":{"description":"Searches contacts, companies, deals, or tickets through HubSpot's official server-side SDK. The connected private-app token remains sealed server-side.","operationId":"searchHubSpot","requestBody":{"content":{"application/json":{"example":{"limit":10,"objectType":"contact","query":"buyer@example.com"},"schema":{"$ref":"#/components/schemas/HubSpotSearchRequest"}}},"description":"HubSpot search.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"objectType":"contact","results":[{"id":"101","properties":{"email":"buyer@example.com"}}],"total":1},"schema":{"$ref":"#/components/schemas/HubSpotSearchResponse"}}},"description":"HubSpot search result."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"409":{"$ref":"#/components/responses/409"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Search HubSpot CRM","tags":["Connectors"]}},"/v1/internal/connections/invalidate":{"post":{"description":"Server-to-server endpoint for products to invalidate a user's connector connection. Unknown users are treated as successful no-ops.","operationId":"invalidateConnection","requestBody":{"content":{"application/json":{"example":{"connector":"canvas","workos_user_id":"user_01HABCDEF"},"schema":{"$ref":"#/components/schemas/InternalInvalidateRequest"}}},"description":"Invalidation target.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"deleted":1,"invalidated":true},"schema":{"$ref":"#/components/schemas/InternalInvalidateResponse"}}},"description":"Invalidation result."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"InternalSecret":[]}],"summary":"Force-disconnect a connector","tags":["Internal"]}},"/v1/internal/events":{"post":{"description":"Internal-secret ingestion used by backend services and test fixtures. Identical to /v1/events except the caller names the owning userId explicitly.","operationId":"ingestInternalCloudEvent","requestBody":{"content":{"application/json":{"example":{"dedupeKey":"internal:test:1","source":"internal","subject":"Synthetic event","userId":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5"},"schema":{"$ref":"#/components/schemas/InternalCloudEventIngestRequest"}}},"description":"Normalized event envelope with explicit owner.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"deduped":true,"eventId":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","routingStatus":"routed"},"schema":{"$ref":"#/components/schemas/CloudEventIngestResponse"}}},"description":"Duplicate dedupeKey: existing event returned."},"202":{"content":{"application/json":{"example":{"deduped":false,"eventId":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","routingStatus":"pending"},"schema":{"$ref":"#/components/schemas/CloudEventIngestResponse"}}},"description":"Event stored, routing enqueued."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"InternalSecret":[]}],"summary":"Ingest a cloud event (server-to-server)","tags":["Internal"]}},"/v1/llm/chat/completions":{"post":{"description":"Credit-gated chat completion endpoint. The gateway estimates and reserves credits, routes the desktop model id to OpenAI or OpenRouter, forwards the request, streams or buffers the upstream response, then settles actual token usage.","operationId":"createChatCompletion","parameters":[{"description":"Required stable key for metered POST retries. Reusing the same key for the same user, route, and method reuses the same credit reservation anchor.","in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}},{"description":"Optional feature/use-case label recorded in LLMUsage for cost allocation.","in":"header","name":"x-solomon-use-case","required":false,"schema":{"type":"string"}},{"description":"Optional sub-use-case label recorded in LLMUsage.","in":"header","name":"x-solomon-sub-use-case","required":false,"schema":{"type":"string"}},{"description":"Optional agent name recorded in LLMUsage.","in":"header","name":"x-solomon-agent-name","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"messages":[{"content":"Summarize this customer.","role":"user"}],"model":"openai/gpt-4.1-mini","stream":true},"schema":{"$ref":"#/components/schemas/LLMChatCompletionsRequest"}}},"description":"OpenAI-compatible chat completions body.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"id":"chatcmpl_123","object":"chat.completion"},"schema":{"$ref":"#/components/schemas/LLMGatewayResponse"}},"text/event-stream":{"example":"data: {\"choices\":[{\"delta\":{\"content\":\"hi\"}}]}\n\ndata: [DONE]\n","schema":{"type":"string"}}},"description":"OpenAI-compatible JSON response, or text/event-stream when stream=true."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"402":{"$ref":"#/components/responses/402"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Proxy OpenAI-compatible chat completion","tags":["LLM"]}},"/v1/llm/completions":{"post":{"description":"Credit-gated legacy completions endpoint. Request and response shape follows OpenAI-compatible /completions semantics.","operationId":"createCompletion","parameters":[{"description":"Required stable key for metered POST retries. Reusing the same key for the same user, route, and method reuses the same credit reservation anchor.","in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}},{"description":"Optional feature/use-case label recorded in LLMUsage for cost allocation.","in":"header","name":"x-solomon-use-case","required":false,"schema":{"type":"string"}},{"description":"Optional sub-use-case label recorded in LLMUsage.","in":"header","name":"x-solomon-sub-use-case","required":false,"schema":{"type":"string"}},{"description":"Optional agent name recorded in LLMUsage.","in":"header","name":"x-solomon-agent-name","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"max_tokens":256,"model":"openai/gpt-4.1-mini","prompt":"Summarize this customer."},"schema":{"$ref":"#/components/schemas/LLMCompletionsRequest"}}},"description":"OpenAI-compatible completions body.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"id":"chatcmpl_123","object":"chat.completion"},"schema":{"$ref":"#/components/schemas/LLMGatewayResponse"}},"text/event-stream":{"example":"data: {\"choices\":[{\"delta\":{\"content\":\"hi\"}}]}\n\ndata: [DONE]\n","schema":{"type":"string"}}},"description":"OpenAI-compatible JSON response, or text/event-stream when stream=true."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"402":{"$ref":"#/components/responses/402"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Proxy OpenAI-compatible legacy completion","tags":["LLM"]}},"/v1/llm/embeddings":{"post":{"description":"Credit-gated embeddings endpoint. The gateway requires a model, reserves credits, forwards the request, and records usage.","operationId":"createEmbedding","parameters":[{"description":"Required stable key for metered POST retries. Reusing the same key for the same user, route, and method reuses the same credit reservation anchor.","in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}},{"description":"Optional feature/use-case label recorded in LLMUsage for cost allocation.","in":"header","name":"x-solomon-use-case","required":false,"schema":{"type":"string"}},{"description":"Optional sub-use-case label recorded in LLMUsage.","in":"header","name":"x-solomon-sub-use-case","required":false,"schema":{"type":"string"}},{"description":"Optional agent name recorded in LLMUsage.","in":"header","name":"x-solomon-agent-name","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"input":["invoice","payment"],"model":"openai/text-embedding-3-small"},"schema":{"$ref":"#/components/schemas/LLMEmbeddingsRequest"}}},"description":"OpenAI-compatible embeddings body.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"id":"chatcmpl_123","object":"chat.completion"},"schema":{"$ref":"#/components/schemas/LLMGatewayResponse"}}},"description":"OpenAI-compatible upstream response."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"402":{"$ref":"#/components/responses/402"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Proxy OpenAI-compatible embeddings","tags":["LLM"]}},"/v1/llm/models":{"get":{"description":"Returns the sorted set of priced model ids the desktop can send to the LLM gateway.","operationId":"listLLMModels","responses":{"200":{"content":{"application/json":{"example":{"data":[{"id":"openai/gpt-4.1-mini"},{"id":"anthropic/claude-sonnet-4-5"}]},"schema":{"$ref":"#/components/schemas/LLMModelsResponse"}}},"description":"Model catalog."},"401":{"$ref":"#/components/responses/401"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"List routable LLM models","tags":["LLM"]}},"/v1/me":{"get":{"description":"Returns the authenticated user's local identity, plan, subscription status, and credit totals. Credit totals include top-level, monthly, and daily buckets consumed by the desktop billing UI.","operationId":"getMe","responses":{"200":{"content":{"application/json":{"example":{"billing":{"plan":"free","status":"active","trialExpiresAt":null,"usage":{"availableCredits":10000,"daily":{"availableCredits":10000,"sanctionedCredits":10000,"usageDay":"2026-06-04","usedCredits":0},"monthly":{"availableCredits":10000,"sanctionedCredits":10000,"usedCredits":0},"sanctionedCredits":10000,"usedCredits":0}},"user":{"email":"kind@solomon-ai.co","id":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5"}},"schema":{"$ref":"#/components/schemas/MeResponse"}}},"description":"Current user and billing state."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Get current user and billing state","tags":["Billing"]}},"/v1/public/mutual-action-plan":{"get":{"description":"Returns only the externally authorized plan revision with internal evidence references removed and policy redactions applied.","operationId":"getPublicMutualActionPlan","parameters":[{"description":"Scoped plan response token. Never put this token in a URL or query parameter.","in":"header","name":"X-Oppulence-Plan-Token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Public mutual action plan.","type":"object"}}},"description":"Scoped public plan."},"404":{"$ref":"#/components/responses/404"}},"summary":"Open a scoped mutual action plan","tags":["Relationship Intelligence"]}},"/v1/public/mutual-action-plan/responses":{"post":{"description":"Appends an idempotent external response for internal review; it never directly changes canonical commitments.","operationId":"respondPublicMutualActionPlan","parameters":[{"description":"Scoped plan response token. Never put this token in a URL or query parameter.","in":"header","name":"X-Oppulence-Plan-Token","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"kind":"confirm","responseId":"response:ab12"},"schema":{"description":"Plan response.","properties":{"comment":{"description":"Counterparty comment.","example":"Waiting on legal.","type":"string"},"itemId":{"description":"Plan item id when applicable.","example":"item:ab12","type":"string"},"kind":{"description":"Response kind.","enum":["confirm","correct","blocked","completed","comment"],"example":"confirm","type":"string"},"proposedValue":{"description":"Proposed correction.","example":"Move due date to Friday.","type":"string"},"responseId":{"description":"Counterparty-generated idempotency key.","example":"response:ab12","type":"string"}},"required":["responseId","kind"],"type":"object"}}},"description":"External response.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Response receipt.","type":"object"}}},"description":"Recorded response."},"400":{"$ref":"#/components/responses/400"},"404":{"$ref":"#/components/responses/404"}},"summary":"Respond to a scoped plan","tags":["Relationship Intelligence"]}},"/v1/relationship-observations/batch":{"post":{"description":"Atomically ingests up to 100 idempotent observations from Gmail, Calendar, Slack, CRM, desktop, or another adapter, then reprojects each affected relationship once.","operationId":"ingestRelationshipObservations","requestBody":{"content":{"application/json":{"example":{"observations":[{"accountDomain":"acme.com","displayName":"Acme","eventType":"commitment_created","externalId":"message-123","source":"gmail"}]},"schema":{"description":"Observation batch.","properties":{"observations":{"description":"Provider-neutral observations.","items":{"description":"Observation input.","properties":{"accountDomain":{"description":"Exact account domain.","example":"acme.com","type":"string"},"displayName":{"description":"Account display name for first ingestion.","example":"Acme","type":"string"},"eventType":{"description":"Normalized event type.","example":"commitment_created","type":"string"},"externalId":{"description":"Provider event id.","example":"message-123","type":"string"},"normalizedFacts":{"additionalProperties":true,"description":"Provider-neutral facts.","type":"object"},"occurredAt":{"description":"Occurrence time.","example":"2026-07-18T17:30:00Z","format":"date-time","type":"string"},"payload":{"additionalProperties":true,"description":"Raw provider payload, sealed at rest.","type":"object"},"primaryEmail":{"description":"Primary contact email.","example":"avery@acme.com","type":"string"},"relationshipId":{"description":"Known relationship id.","example":"9c8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"source":{"description":"Evidence source.","example":"gmail","type":"string"},"sourceAccountId":{"description":"Provider account id.","example":"me@company.com","type":"string"},"sourceVersion":{"description":"Provider event version.","example":"1","type":"string"},"summary":{"description":"Bounded evidence summary.","example":"We promised the security packet.","type":"string"}},"required":["source","externalId","eventType"],"type":"object"},"type":"array"}},"required":["observations"],"type":"object"}}},"description":"Observation batch.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Observation, relationship, and duplicate status per input.","type":"object"}}},"description":"Ingestion results."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Ingest relationship observations","tags":["Relationship Intelligence"]}},"/v1/relationship-recommendations/{actionId}/approve":{"post":{"description":"Relationship-intelligence alias for the governed action approval transition.","operationId":"approveRelationshipRecommendation","parameters":[{"description":"Recommendation/action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"acceptRisk":false},"schema":{"description":"Approve request.","properties":{"acceptRisk":{"description":"Explicitly accept a review-required decision.","example":false,"type":"boolean"}},"type":"object"}}},"description":"Approval options.","required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Approved recommendation."},"401":{"$ref":"#/components/responses/401"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Approve a recommendation","tags":["Relationship Intelligence"]}},"/v1/relationship-recommendations/{actionId}/reject":{"post":{"description":"Relationship-intelligence alias for rejecting the current action revision.","operationId":"rejectRelationshipRecommendation","parameters":[{"description":"Recommendation/action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"reason":"Not the right next move."},"schema":{"description":"Reject request.","properties":{"reason":{"description":"Rejection reason.","example":"Not the right next move.","type":"string"}},"required":["reason"],"type":"object"}}},"description":"Rejection.","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Rejected recommendation."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Reject a recommendation","tags":["Relationship Intelligence"]}},"/v1/relationship-sources/status":{"get":{"description":"Returns freshness and failure state for each relationship evidence source.","operationId":"getRelationshipSourceStatuses","responses":{"200":{"content":{"application/json":{"schema":{"description":"Source status list.","properties":{"sources":{"description":"Sources.","items":{"$ref":"#/components/schemas/RelationshipSourceStatus"},"type":"array"}},"type":"object"}}},"description":"Evidence source health."},"401":{"$ref":"#/components/responses/401"}},"security":[{"BearerAuth":[]}],"summary":"Get source health","tags":["Relationship Intelligence"]}},"/v1/relationships":{"get":{"description":"Lists canonical relationship state with optional text, lifecycle, health, and engagement filters.","operationId":"listRelationships","parameters":[{"description":"Account, domain, or contact search.","in":"query","name":"q","required":false,"schema":{"type":"string"}},{"description":"Lifecycle filter.","in":"query","name":"lifecycle","required":false,"schema":{"type":"string"}},{"description":"Health filter.","in":"query","name":"health","required":false,"schema":{"type":"string"}},{"description":"Engagement filter.","in":"query","name":"engagement","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Relationship list.","properties":{"relationships":{"description":"Relationships.","items":{"$ref":"#/components/schemas/RevenueRelationship"},"type":"array"}},"type":"object"}}},"description":"Relationships."},"401":{"$ref":"#/components/responses/401"}},"security":[{"BearerAuth":[]}],"summary":"List relationships","tags":["Relationship Intelligence"]},"post":{"description":"Records a canonical relationship in the caller's workspace.","operationId":"createRelationship","requestBody":{"content":{"application/json":{"example":{"displayName":"Jordan Buyer","kind":"person","primaryEmail":"buyer@example.com"},"schema":{"description":"Create request.","properties":{"accountDomain":{"description":"Account domain.","example":"example.com","type":"string"},"displayName":{"description":"Display name.","example":"Jordan Buyer","type":"string"},"kind":{"description":"Relationship kind.","enum":["person","company","customer","opportunity","referral","partner"],"example":"person","type":"string"},"primaryEmail":{"description":"Primary email.","example":"buyer@example.com","type":"string"},"summary":{"description":"Summary.","example":"Warm lead from the April demo.","type":"string"}},"required":["kind","displayName"],"type":"object"}}},"description":"Relationship.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueRelationship"}}},"description":"Created relationship."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"}},"security":[{"BearerAuth":[]}],"summary":"Create a relationship","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}":{"get":{"description":"Returns living relationship state, governed recommendations, participants, and commitments.","operationId":"getRelationship","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Relationship detail.","properties":{"actions":{"description":"Actions for this relationship.","items":{"$ref":"#/components/schemas/RevenueAction"},"type":"array"},"commitmentDependencies":{"description":"Evidence-backed commitment graph edges.","items":{"$ref":"#/components/schemas/CommitmentDependency"},"type":"array"},"commitments":{"description":"Open and completed commitments.","items":{"$ref":"#/components/schemas/RelationshipCommitment"},"type":"array"},"intelligence":{"$ref":"#/components/schemas/RelationshipIntelligence"},"participants":{"description":"Relationship participants.","items":{"$ref":"#/components/schemas/RelationshipParticipant"},"type":"array"},"recommendations":{"description":"Governed recommendations.","items":{"$ref":"#/components/schemas/RevenueAction"},"type":"array"},"relationship":{"$ref":"#/components/schemas/RevenueRelationship"}},"type":"object"}}},"description":"Relationship detail."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Get relationship mission control","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/changes":{"get":{"description":"Returns immutable projection snapshots so operators can see what changed and why.","operationId":"getRelationshipChanges","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Snapshot list.","properties":{"snapshots":{"description":"Snapshots.","items":{"$ref":"#/components/schemas/RelationshipStateSnapshot"},"type":"array"}},"type":"object"}}},"description":"State changes."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Get relationship changes","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/commitment-dependencies":{"post":{"description":"Creates an evidence-backed dependency after enforcing tenant and relationship scope and rejecting graph cycles.","operationId":"createCommitmentDependency","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"evidenceRefs":["relationship-observation:ab12"],"fromCommitmentId":"8b8dfa9b-a7b2-46ea-982c-622a914c00e5","kind":"blocks","toCommitmentId":"26cdbdc9-d0fc-4f8c-8660-2f0d62cfef51"},"schema":{"description":"Commitment dependency request.","properties":{"evidenceRefs":{"description":"Evidence references.","items":{"description":"Reference.","example":"relationship-observation:ab12","type":"string"},"type":"array"},"fromCommitmentId":{"description":"Origin commitment id.","example":"8b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"kind":{"description":"Dependency semantics.","enum":["blocks","requires","supersedes"],"example":"blocks","type":"string"},"toCommitmentId":{"description":"Target commitment id.","example":"8b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"}},"required":["fromCommitmentId","toCommitmentId","kind","evidenceRefs"],"type":"object"}}},"description":"Dependency.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitmentDependency"}}},"description":"Created dependency."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Create a commitment dependency","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/commitment-recovery/run":{"post":{"description":"Reconciles due commitments against bounded fresh evidence, closes only explicit fulfillment, and queues governed recovery proposals otherwise.","operationId":"runCommitmentRecovery","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{},"schema":{"description":"Recovery request.","properties":{},"type":"object"}}},"description":"Empty request.","required":false},"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Recovery evaluation result.","type":"object"}}},"description":"Recovery evaluations."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Run commitment recovery","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/commitments/{commitmentId}/events":{"get":{"description":"Returns the append-only transition history for one commitment.","operationId":"getCommitmentEvents","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Commitment id.","in":"path","name":"commitmentId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Commitment history.","properties":{"events":{"description":"Ordered immutable events.","items":{"$ref":"#/components/schemas/CommitmentEvent"},"type":"array"}},"required":["events"],"type":"object"}}},"description":"Commitment events."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Get commitment history","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/commitments/{commitmentId}/transitions":{"post":{"description":"Validates the state machine and appends one idempotent event before atomically updating the materialized projection.","operationId":"appendCommitmentTransition","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Commitment id.","in":"path","name":"commitmentId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"evidenceRefs":["counterparty:accepted"],"idempotencyKey":"ui:accept:ab12","kind":"accepted"},"schema":{"description":"Commitment transition.","properties":{"action":{"description":"Replacement action for renegotiation.","example":"Send revised packet.","type":"string"},"blocker":{"description":"Blocker detail.","example":"Waiting on legal.","type":"string"},"dueAt":{"description":"Replacement due date.","example":"2026-08-07T17:00:00Z","format":"date-time","type":"string"},"evidenceRefs":{"description":"Evidence references.","items":{"description":"Reference.","example":"relationship-observation:ab12","type":"string"},"type":"array"},"idempotencyKey":{"description":"Stable source event id.","example":"ui:accept:ab12","type":"string"},"kind":{"description":"Event kind.","enum":["internally_confirmed","offered","accepted","disputed","blocked","unblocked","due_date_changed","renegotiated","fulfilled","cancelled","superseded"],"example":"accepted","type":"string"},"reason":{"description":"Optional reason.","example":"Counterparty accepted in writing.","type":"string"}},"required":["kind","idempotencyKey"],"type":"object"}}},"description":"Transition.","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RelationshipCommitment"}}},"description":"Updated commitment."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Append a commitment transition","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/contradictions/{caseId}/resolve":{"post":{"description":"Records the user's selected evidence side as a top-authority correction without rewriting either source.","operationId":"resolveRelationshipContradiction","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Contradiction case id.","in":"path","name":"caseId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"selectedAssertionId":"assertion:ab12"},"schema":{"description":"Contradiction resolution.","properties":{"reason":{"description":"Optional rationale.","example":"CRM was updated after the meeting.","type":"string"},"selectedAssertionId":{"description":"Selected assertion id.","example":"assertion:ab12","type":"string"}},"required":["selectedAssertionId"],"type":"object"}}},"description":"Resolution.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Relationship detail result.","type":"object"}}},"description":"Updated relationship and intelligence."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Resolve a typed contradiction","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/conversation-corrections":{"post":{"description":"Resolves a focused word, speaker, entity, or material-claim review item. State-affecting corrections append a top-precedence user assertion and reproject deterministically.","operationId":"correctConversationEvidence","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"correctedValue":"Avery Chen","reason":"Avery was the speaker.","reviewItemId":"review:ab12"},"schema":{"description":"Conversation correction.","properties":{"correctedValue":{"description":"Human-corrected value.","example":"Avery Chen","type":"string"},"reason":{"description":"Correction reason.","example":"Avery was the speaker.","type":"string"},"reviewItemId":{"description":"Focused review item id.","example":"review:ab12","type":"string"}},"required":["reviewItemId","correctedValue","reason"],"type":"object"}}},"description":"Focused correction.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"description":"Correction result.","properties":{"intelligence":{"$ref":"#/components/schemas/RelationshipIntelligence"},"relationship":{"$ref":"#/components/schemas/RevenueRelationship"}},"required":["relationship","intelligence"],"type":"object"}}},"description":"Corrected relationship and refreshed intelligence."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Correct reviewed conversation evidence","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/conversation-decisions":{"post":{"description":"Approves, corrects, rejects, or defers one evidence-backed semantic candidate. A stale baseline returns 409 and no state mutation.","operationId":"decideConversationChange","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"kind":"approve","reason":"Customer stated this directly.","reviewItemId":"review:ab12"},"schema":{"description":"Conversation review decision.","properties":{"correctedValue":{"description":"Required replacement for correct.","example":"Security review is complete.","type":"string"},"deferUntil":{"description":"Future reminder for defer.","example":"2026-08-01T14:00:00Z","format":"date-time","type":"string"},"kind":{"description":"Decision kind.","enum":["approve","correct","reject","defer"],"example":"approve","type":"string"},"reason":{"description":"Decision reason.","example":"Customer clarified this in the meeting.","type":"string"},"reviewItemId":{"description":"Review item id.","example":"review:ab12","type":"string"}},"required":["reviewItemId","kind"],"type":"object"}}},"description":"Review decision.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"description":"Decision result.","properties":{"intelligence":{"$ref":"#/components/schemas/RelationshipIntelligence"},"relationship":{"$ref":"#/components/schemas/RevenueRelationship"}},"required":["relationship","intelligence"],"type":"object"}}},"description":"Updated relationship and refreshed review queue."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Decide a proposed conversation change","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/conversation-deletion":{"post":{"description":"Evaluates legal hold at execution time, removes server-side content transactionally, and returns an idempotent per-target receipt. Device and provider work remains pending until separately verified.","operationId":"requestConversationDeletion","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"requestId":"delete:ab12"},"schema":{"description":"Deletion request.","properties":{"requestId":{"description":"Idempotency key.","example":"delete:ab12","type":"string"}},"required":["requestId"],"type":"object"}}},"description":"Deletion request.","required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDeletionReceipt"}}},"description":"Deletion receipt."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Request conversation deletion","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/conversation-policy":{"get":{"description":"Returns all applicable layers and the monotonically resolved effective policy.","operationId":"getConversationPolicy","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Conversation policy result.","type":"object"}}},"description":"Policy layers and effective policy."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Inspect conversation policy","tags":["Relationship Intelligence"]},"put":{"description":"Appends authorized policy-layer versions; lower layers may only make handling stricter.","operationId":"putConversationPolicy","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"description":"Policy update.","properties":{"layers":{"description":"Versioned policy layers.","items":{"additionalProperties":true,"description":"Conversation policy layer.","type":"object"},"type":"array"}},"required":["layers"],"type":"object"}}},"description":"Policy layers.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Conversation policy result.","type":"object"}}},"description":"Resolved effective policy."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Update conversation policy","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/corrections":{"post":{"description":"Appends a user correction assertion and deterministically reprojects the relationship. Source evidence is never overwritten.","operationId":"correctRelationship","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"dimension":"health","reason":"The review happened yesterday.","value":"healthy"},"schema":{"description":"Relationship correction.","properties":{"dimension":{"description":"Corrected state dimension.","enum":["lifecycle","engagement","sentiment","health","next_action"],"example":"health","type":"string"},"reason":{"description":"Why the model is wrong.","example":"The review happened yesterday.","type":"string"},"value":{"description":"Correct value.","example":"healthy","type":"string"}},"required":["dimension","value","reason"],"type":"object"}}},"description":"Correction.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueRelationship"}}},"description":"Reprojected relationship."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Correct relationship state","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/evidence/{evidenceId}":{"get":{"description":"Returns one observation plus its decrypted raw payload. Tenant ownership is enforced before decryption.","operationId":"getRelationshipEvidence","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Observation id.","in":"path","name":"evidenceId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Evidence result.","properties":{"observation":{"$ref":"#/components/schemas/RelationshipObservation"},"payload":{"additionalProperties":true,"description":"Decrypted provider payload.","type":"object"}},"type":"object"}}},"description":"Source evidence."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Open source evidence","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/mutual-action-plans":{"post":{"description":"Creates an evidence-backed plan only from accepted or open commitments.","operationId":"createMutualActionPlan","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"commitmentIds":["8b8dfa9b-a7b2-46ea-982c-622a914c00e5"]},"schema":{"description":"Plan create request.","properties":{"commitmentIds":{"description":"Commitment ids.","items":{"description":"Commitment id.","example":"8b8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"type":"array"}},"required":["commitmentIds"],"type":"object"}}},"description":"Accepted commitments.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Mutual action plan.","type":"object"}}},"description":"Draft plan."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Create a mutual action plan","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/mutual-action-plans/{planId}":{"put":{"description":"Appends a validated revision and invalidates any approval bound to the prior hash.","operationId":"reviseMutualActionPlan","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Mutual action plan id.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"description":"Plan revision request.","properties":{"items":{"description":"Plan items.","items":{"additionalProperties":true,"description":"Mutual action plan item.","type":"object"},"type":"array"}},"required":["items"],"type":"object"}}},"description":"Replacement items.","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Mutual action plan.","type":"object"}}},"description":"Revised plan."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Revise a mutual action plan","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/mutual-action-plans/{planId}/approve":{"post":{"description":"Binds internal approval to the exact current revision hash.","operationId":"approveMutualActionPlan","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Mutual action plan id.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{},"schema":{"description":"Plan approval request.","properties":{},"type":"object"}}},"description":"Empty request.","required":false},"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Mutual action plan.","type":"object"}}},"description":"Approved plan."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Approve a plan revision","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/mutual-action-plans/{planId}/share":{"post":{"description":"Re-evaluates effective policy, creates a scoped expiring token, stores only its hash, and queues the exact approved revision for operator approval.","operationId":"shareMutualActionPlan","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Mutual action plan id.","in":"path","name":"planId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{},"schema":{"description":"Plan share request.","properties":{},"type":"object"}}},"description":"Empty request.","required":false},"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":true,"description":"Plan share result.","type":"object"}}},"description":"Shared plan metadata and one-time response token."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Queue an approved plan share","tags":["Relationship Intelligence"]}},"/v1/relationships/{relationshipId}/timeline":{"get":{"description":"Returns the latest immutable observations for a relationship.","operationId":"getRelationshipTimeline","parameters":[{"description":"Relationship id.","in":"path","name":"relationshipId","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Maximum observations (1-100).","in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Observation list.","properties":{"observations":{"description":"Observations.","items":{"$ref":"#/components/schemas/RelationshipObservation"},"type":"array"}},"type":"object"}}},"description":"Evidence timeline."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Get evidence timeline","tags":["Relationship Intelligence"]}},"/v1/revenue-actions":{"get":{"description":"Lists/filters the queue ordered by priority. The default page is the ten highest-priority open actions.","operationId":"listRevenueActions","parameters":[{"description":"Queue status filter, or all.","in":"query","name":"queueStatus","required":false,"schema":{"enum":["open","snoozed","dismissed","handled","all"],"type":"string"}},{"description":"Page size (max 100, default 10).","in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Action list.","properties":{"actions":{"description":"Actions.","items":{"$ref":"#/components/schemas/RevenueAction"},"type":"array"}},"type":"object"}}},"description":"Queue page."},"401":{"$ref":"#/components/responses/401"}},"security":[{"BearerAuth":[]}],"summary":"List the action queue","tags":["Revenue"]},"post":{"description":"Proposes a manual queue action with revision 1 and an immutable revision snapshot. A duplicate dedupe key returns the existing item.","operationId":"createRevenueAction","requestBody":{"content":{"application/json":{"schema":{"description":"Create request.","properties":{"actionType":{"description":"Action type.","enum":["warm_follow_up","proposal_nudge","referral_reconnect","customer_risk","meeting_follow_up","meeting_recap","crm_update","follow_up_task","calendar_hold","commitment_rescue"],"example":"warm_follow_up","type":"string"},"channel":{"description":"Delivery channel.","enum":["email","slack","call","crm_task","crm","task","calendar"],"example":"email","type":"string"},"dueAt":{"description":"Due time.","example":"2026-07-15T00:00:00Z","format":"date-time","nullable":true,"type":"string"},"executionMode":{"description":"Execution mode.","enum":["draft","send"],"example":"draft","type":"string"},"priorityComponents":{"additionalProperties":true,"description":"Per-component priority breakdown.","type":"object"},"priorityScore":{"description":"Priority (0-100).","example":80,"type":"integer"},"proposedMessage":{"description":"Proposed body.","example":"Hi Jordan — circling back as promised...","type":"string"},"proposedSubject":{"description":"Proposed subject.","example":"Following up as promised","type":"string"},"reason":{"description":"Evidence-backed reason.","example":"They asked for a follow-up in July.","type":"string"},"recipientEmail":{"description":"Recipient email.","example":"buyer@example.com","type":"string"},"relationshipId":{"description":"Owning relationship id.","example":"9c8dfa9b-a7b2-46ea-982c-622a914c00e5","format":"uuid","type":"string"},"senderAccountRef":{"description":"Sender account reference.","example":"gmail:me@company.com","type":"string"}},"required":["relationshipId","actionType","channel","reason"],"type":"object"}}},"description":"Action.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Created action."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Create a manual action","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}":{"get":{"description":"Returns one action with relationship context.","operationId":"getRevenueAction","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Action."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Get an action","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/approve":{"post":{"description":"Approves the current revision. Send-mode actions require a passed (or explicitly risk-accepted review_required) unexpired decision bound to the exact revision; blocked actions can never be approved.","operationId":"approveRevenueAction","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"acceptRisk":false},"schema":{"description":"Approve request.","properties":{"acceptRisk":{"description":"Explicitly accept a review_required decision.","example":false,"type":"boolean"}},"type":"object"}}},"description":"Approval options.","required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Approved action."},"401":{"$ref":"#/components/responses/401"},"402":{"content":{"application/problem+json":{"example":{"code":"subscription_required","detail":"an active subscription is required to act on actions","requestId":"req-abc123","status":402,"title":"Payment Required","type":"https://api.rowboat.dev/problems/subscription_required"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Acting on actions requires a paid subscription."},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"example":{"code":"blocked","detail":"action is blocked by policy","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/blocked"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Invariant violation: blocked, no decision, expired decision, or review required."}},"security":[{"BearerAuth":[]}],"summary":"Approve an action","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/audit":{"get":{"description":"Returns the full observe, decision, approval, execution, and outcome chain for one action.","operationId":"getRevenueActionAudit","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Audit chain.","properties":{"action":{"$ref":"#/components/schemas/RevenueAction"},"decisions":{"description":"Policy decision snapshots.","items":{"$ref":"#/components/schemas/RevenuePolicyDecision"},"type":"array"},"outcomes":{"description":"Observed outcomes.","items":{"$ref":"#/components/schemas/RevenueOutcome"},"type":"array"},"revisions":{"description":"Immutable revision snapshots.","items":{"additionalProperties":true,"description":"Revision snapshot.","type":"object"},"type":"array"}},"type":"object"}}},"description":"Audit chain."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Get the audit chain","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/dismiss":{"post":{"description":"Dismisses the action with a reason label and records the dismissed outcome.","operationId":"dismissRevenueAction","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"reason":"already_handled"},"schema":{"description":"Dismiss request.","properties":{"reason":{"description":"Reason label.","example":"already_handled","type":"string"}},"type":"object"}}},"description":"Dismissal reason.","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Dismissed action."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Dismiss an action","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/edit":{"post":{"description":"Creates a new revision and invalidates the previous policy decision and approval. Editing is refused once execution has started.","operationId":"editRevenueAction","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"description":"Edit request.","properties":{"actionType":{"description":"Action type.","enum":["warm_follow_up","proposal_nudge","referral_reconnect","customer_risk","meeting_follow_up"],"example":"warm_follow_up","type":"string"},"channel":{"description":"Channel.","enum":["email","slack","call","crm_task"],"example":"email","type":"string"},"executionMode":{"description":"Execution mode.","enum":["draft","send"],"example":"draft","type":"string"},"proposedMessage":{"description":"Proposed body.","example":"Updated body","nullable":true,"type":"string"},"proposedSubject":{"description":"Proposed subject.","example":"Updated subject","nullable":true,"type":"string"},"reason":{"description":"Reason.","example":"Updated context.","nullable":true,"type":"string"},"recipientEmail":{"description":"Recipient email.","example":"buyer@example.com","nullable":true,"type":"string"},"senderAccountRef":{"description":"Sender account reference.","example":"gmail:me@company.com","nullable":true,"type":"string"}},"type":"object"}}},"description":"Fields to change; omitted fields keep their value.","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Action at its new revision."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"example":{"code":"not_editable","detail":"execution already started; the action is immutable","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/not_editable"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Execution already started; the action is immutable."}},"security":[{"BearerAuth":[]}],"summary":"Edit an action","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/evaluate":{"post":{"description":"Requests or retries the OutboundConsole preflight for the current revision and stores the immutable decision snapshot. A fresh unexpired decision for the same revision is returned without provider cost. Facade unavailability keeps the action pending (fail closed).","operationId":"evaluateRevenueAction","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenuePolicyDecision"}}},"description":"Decision snapshot."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"503":{"content":{"application/problem+json":{"example":{"code":"facade_unavailable","detail":"policy preflight unavailable; the action stays pending","requestId":"req-abc123","status":503,"title":"Service Unavailable","type":"https://api.rowboat.dev/problems/facade_unavailable"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Policy facade unavailable; the action stays pending."}},"security":[{"BearerAuth":[]}],"summary":"Request policy preflight","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/execute":{"post":{"description":"Executes the approved current revision exactly once through the assigned execution owner, with an idempotency key derived from the action and revision. A duplicate execute returns the existing result. A lost provider result is marked ambiguous and never automatically resent.","operationId":"executeRevenueAction","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Action after execution."},"401":{"$ref":"#/components/responses/401"},"402":{"content":{"application/problem+json":{"example":{"code":"subscription_required","detail":"an active subscription is required to act on actions","requestId":"req-abc123","status":402,"title":"Payment Required","type":"https://api.rowboat.dev/problems/subscription_required"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Acting on actions requires a paid subscription."},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"example":{"code":"not_approved","detail":"action is not approved for its current revision","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/not_approved"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Invariant violation: not approved, blocked, expired decision, or workspace not linked for sends."}},"security":[{"BearerAuth":[]}],"summary":"Execute an action","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/outcomes":{"post":{"description":"Appends an observed outcome idempotently on (action, source, sourceEventId); the duplicate returns the stored row.","operationId":"recordRevenueActionOutcome","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"kind":"replied","source":"gmail","sourceEventId":"msg_01"},"schema":{"description":"Outcome request.","properties":{"kind":{"description":"Outcome kind.","enum":["sent","delivered","bounced","replied","meeting_booked","won","lost","dismissed","bad_recommendation"],"example":"replied","type":"string"},"metadata":{"additionalProperties":true,"description":"Bounded metadata.","type":"object"},"occurredAt":{"description":"When the outcome occurred.","example":"2026-07-12T14:00:00Z","format":"date-time","nullable":true,"type":"string"},"source":{"description":"Observing source.","enum":["gmail","calendar","crm","user","outbound"],"example":"gmail","type":"string"},"sourceEventId":{"description":"Source event id for deduplication.","example":"msg_01","type":"string"}},"required":["kind","source","sourceEventId"],"type":"object"}}},"description":"Outcome.","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueOutcome"}}},"description":"Recorded outcome."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Record an outcome","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/reject":{"post":{"description":"Rejects the current revision with a reason.","operationId":"rejectRevenueAction","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"reason":"wrong_recipient"},"schema":{"description":"Reject request.","properties":{"reason":{"description":"Reason.","example":"wrong_recipient","type":"string"}},"type":"object"}}},"description":"Rejection reason.","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Rejected action."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"409":{"$ref":"#/components/responses/409"}},"security":[{"BearerAuth":[]}],"summary":"Reject an action","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/snooze":{"post":{"description":"Parks the action until a bounded future timestamp (at most 90 days).","operationId":"snoozeRevenueAction","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"until":"2026-07-20T09:00:00Z"},"schema":{"description":"Snooze request.","properties":{"until":{"description":"Wake time.","example":"2026-07-20T09:00:00Z","format":"date-time","type":"string"}},"required":["until"],"type":"object"}}},"description":"Wake time.","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueAction"}}},"description":"Snoozed action."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Snooze an action","tags":["Revenue"]}},"/v1/revenue-actions/{actionId}/source-body":{"get":{"description":"Returns the plain-text body of the original email behind this action (RFC 031 Layer 3), served from the sealed short-TTL cache or fetched from Gmail on demand. 404 when no source message is linked or the body is unavailable.","operationId":"getRevenueActionSourceBody","parameters":[{"description":"Action id.","in":"path","name":"actionId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Body.","properties":{"body":{"description":"Plain-text body.","example":"Hi — following up on the proposal...","type":"string"}},"type":"object"}}},"description":"Original email body."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Get the original email body","tags":["Revenue"]}},"/v1/revenue-digest":{"get":{"description":"Returns the digest content the scheduled email is built from: the top open loops and running impact counts.","operationId":"getRevenueDigest","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueDigest"}}},"description":"Digest content."},"401":{"$ref":"#/components/responses/401"}},"security":[{"BearerAuth":[]}],"summary":"Preview the proactive digest","tags":["Revenue"]}},"/v1/revenue-impact":{"get":{"description":"Returns the aggregate ROI picture for the caller: actions surfaced, triage breakdown, executions, outcomes, reply/meeting rates, and per-detector contribution.","operationId":"getRevenueImpact","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueImpact"}}},"description":"Impact summary."},"401":{"$ref":"#/components/responses/401"}},"security":[{"BearerAuth":[]}],"summary":"Get the revenue impact summary","tags":["Revenue"]}},"/v1/revenue-leak-scans":{"post":{"description":"Starts a bounded historical scan over the user's connected Gmail (deterministic detectors, draft-first actions). One scan runs per workspace at a time; poll the scan id for progress.","operationId":"startRevenueLeakScan","requestBody":{"content":{"application/json":{"example":{"lookbackDays":90},"schema":{"description":"Scan request.","properties":{"lookbackDays":{"description":"Historical lookback in days (default 90, max 365).","example":90,"type":"integer"}},"type":"object"}}},"description":"Scan options.","required":false},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueLeakScan"}}},"description":"Scan started."},"401":{"$ref":"#/components/responses/401"},"409":{"content":{"application/problem+json":{"example":{"code":"scan_unavailable","detail":"revenue: scan unavailable: a scan is already running","requestId":"req-abc123","status":409,"title":"Conflict","type":"https://api.rowboat.dev/problems/scan_unavailable"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A scan is already running, or no scan source is configured."}},"security":[{"BearerAuth":[]}],"summary":"Start a revenue leak scan","tags":["Revenue"]}},"/v1/revenue-leak-scans/{scanId}":{"get":{"description":"Returns progress, counts, errors, and source freshness for one scan.","operationId":"getRevenueLeakScan","parameters":[{"description":"Scan id.","in":"path","name":"scanId","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueLeakScan"}}},"description":"Scan state."},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"}},"security":[{"BearerAuth":[]}],"summary":"Get scan progress","tags":["Revenue"]}},"/v1/revenue-search":{"get":{"description":"Natural-language search over the caller's Layer-2 signals (RFC 031). Returns available=false with no matches when semantic memory is not configured.","operationId":"revenueSemanticSearch","parameters":[{"description":"Search query.","in":"query","name":"q","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"description":"Search result.","properties":{"available":{"description":"Whether semantic memory is configured.","example":true,"type":"boolean"},"matches":{"description":"Ranked matches.","items":{"description":"Match.","properties":{"classification":{"description":"Signal class.","enum":["deal","invoice","client","referral","other"],"example":"deal","type":"string"},"counterparty":{"description":"Counterparty email.","example":"buyer@example.com","type":"string"},"score":{"description":"Cosine similarity.","example":0.82,"type":"number"},"subject":{"description":"Thread subject.","example":"Proposal follow-up","type":"string"},"summary":{"description":"Derived summary.","example":"Unanswered proposal from 10 days ago.","type":"string"},"threadId":{"description":"Provider thread id.","example":"thr_01","type":"string"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"Ranked matches."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"}},"security":[{"BearerAuth":[]}],"summary":"Semantic search over mail","tags":["Revenue"]}},"/v1/revenue-workspaces/current":{"get":{"description":"Returns the caller's revenue workspace mapping and preflight health, creating the local-mode workspace on first touch.","operationId":"getRevenueWorkspace","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueWorkspace"}}},"description":"Current workspace."},"401":{"$ref":"#/components/responses/401"}},"security":[{"BearerAuth":[]}],"summary":"Get current revenue workspace","tags":["Revenue"]}},"/v1/revenue-workspaces/link":{"post":{"description":"Completes the OutboundConsole workspace link and switches the workspace to linked mode. Requires a configured policy facade; without one the call fails closed.","operationId":"linkRevenueWorkspace","requestBody":{"content":{"application/json":{"example":{"outboundOrganizationId":"org_01ABC","outboundWorkspaceId":"ws_01ABC"},"schema":{"description":"Link request.","properties":{"outboundOrganizationId":{"description":"OutboundConsole organization id.","example":"org_01ABC","type":"string"},"outboundWorkspaceId":{"description":"OutboundConsole workspace id.","example":"ws_01ABC","type":"string"}},"required":["outboundWorkspaceId"],"type":"object"}}},"description":"OutboundConsole identifiers.","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueWorkspace"}}},"description":"Linked workspace."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"503":{"content":{"application/problem+json":{"example":{"code":"facade_unavailable","detail":"policy preflight unavailable; the action stays pending","requestId":"req-abc123","status":503,"title":"Service Unavailable","type":"https://api.rowboat.dev/problems/facade_unavailable"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Policy facade unavailable; the link fails closed."}},"security":[{"BearerAuth":[]}],"summary":"Link the OutboundConsole workspace","tags":["Revenue"]}},"/v1/search/exa":{"post":{"description":"Credit-gated Exa /search proxy. The request body is forwarded unchanged and the upstream JSON response is returned unchanged.","operationId":"searchExa","parameters":[{"description":"Required stable key for metered POST retries. Reusing the same key for the same user, route, and method reuses the same credit reservation anchor.","in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"numResults":5,"query":"recent fintech accounts receivable trends","type":"neural"},"schema":{"$ref":"#/components/schemas/ExaSearchRequest"}}},"description":"Exa /search request body.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"results":[{"title":"Example result","url":"https://example.com"}]},"schema":{"$ref":"#/components/schemas/ExaSearchResponse"}}},"description":"Exa search response."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"402":{"$ref":"#/components/responses/402"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Run Exa search","tags":["Search"]}},"/v1/slack-oauth/claim":{"post":{"description":"Requires the authenticated user to match the user that started the install, atomically consumes the one-time ticket, and persists the workspace connection. The bot token stays server-held.","operationId":"claimSlackOAuth","requestBody":{"content":{"application/json":{"example":{"session":"state_abc123"},"schema":{"$ref":"#/components/schemas/SlackClaimRequest"}}},"description":"Slack install session ticket.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"botUserId":"U0BOT","connected":true,"scope":"channels:history,channels:read","teamId":"T0EXAMPLE","teamName":"Acme"},"schema":{"$ref":"#/components/schemas/SlackClaimResponse"}}},"description":"Connected workspace metadata."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"403":{"$ref":"#/components/responses/403"},"404":{"$ref":"#/components/responses/404"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The browser install is incomplete, or the workspace is already owned by another Rowboat account."},"410":{"$ref":"#/components/responses/410"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Claim Slack workspace connection","tags":["Slack OAuth"]}},"/v1/slack-oauth/start":{"post":{"description":"Creates a one-time state ticket bound to the authenticated Rowboat user and returns the Slack install URL for the desktop to open.","operationId":"startSlackOAuth","responses":{"200":{"content":{"application/json":{"example":{"authorizeUrl":"https://slack.com/oauth/v2/authorize?..."},"schema":{"properties":{"authorizeUrl":{"format":"uri","type":"string"}},"required":["authorizeUrl"],"type":"object"}}},"description":"Bound Slack authorization URL."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"},"502":{"$ref":"#/components/responses/502"}},"security":[{"BearerAuth":[]}],"summary":"Start Slack workspace install","tags":["Slack OAuth"]}},"/v1/slack-oauth/thread/post":{"post":{"description":"Posts an explicitly approved reply into a connected managed Slack thread using the server-held Slack app token. The token and message text are never returned.","operationId":"postSlackThreadReply","requestBody":{"content":{"application/json":{"example":{"channel":"C01234567","teamId":"T0EXAMPLE","text":"I can take this one.","threadTs":"1700000000.000100"},"schema":{"$ref":"#/components/schemas/SlackThreadPostRequest"}}},"description":"Slack reply target and text.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"channel":"C01234567","ok":true,"teamId":"T0EXAMPLE","threadTs":"1700000000.000100"},"schema":{"$ref":"#/components/schemas/SlackThreadPostResponse"}}},"description":"Slack post accepted."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Post Slack thread reply","tags":["Slack OAuth"]}},"/v1/slack-oauth/thread/read":{"post":{"description":"Reads messages from a connected managed Slack workspace using the server-held Slack app token. The token is never returned to the desktop.","operationId":"readSlackThread","requestBody":{"content":{"application/json":{"example":{"channel":"C01234567","limit":25,"teamId":"T0EXAMPLE","threadTs":"1700000000.000100"},"schema":{"$ref":"#/components/schemas/SlackThreadReadRequest"}}},"description":"Slack thread target.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"channel":"C01234567","messages":[{"text":"Can you summarize this?","ts":"1700000000.000100","user":"U01234567"}],"teamId":"T0EXAMPLE","threadTs":"1700000000.000100"},"schema":{"$ref":"#/components/schemas/SlackThreadReadResponse"}}},"description":"Slack thread messages."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"404":{"$ref":"#/components/responses/404"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Read Slack thread","tags":["Slack OAuth"]}},"/v1/slack-oauth/workspaces":{"get":{"description":"Returns the authenticated user's managed Slack workspace connections. Bot tokens are never returned.","operationId":"listSlackWorkspaces","responses":{"200":{"content":{"application/json":{"example":{"workspaces":[{"connectedAt":"2026-06-04T20:38:00Z","scopes":["channels:history","chat:write"],"teamId":"T0EXAMPLE"}]},"schema":{"$ref":"#/components/schemas/SlackWorkspacesResponse"}}},"description":"Connected Slack workspaces."},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"List Slack workspace connections","tags":["Slack OAuth"]}},"/v1/slack-oauth/workspaces/{teamId}":{"delete":{"description":"Idempotently deletes the authenticated user's managed Slack workspace connection for the given team id.","operationId":"deleteSlackWorkspace","parameters":[{"description":"Slack workspace/team id.","in":"path","name":"teamId","required":true,"schema":{"description":"Slack team id.","example":"T0EXAMPLE","type":"string"}}],"responses":{"204":{"description":"Workspace disconnected or was already absent."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"security":[{"BearerAuth":[]}],"summary":"Disconnect Slack workspace","tags":["Slack OAuth"]}},"/v1/voice/text-to-speech/{voiceId}":{"post":{"description":"Credit-gated ElevenLabs proxy. The text field is used for per-character credit charging and the full body is forwarded to ElevenLabs. Successful responses stream audio bytes back to the desktop.","operationId":"textToSpeech","parameters":[{"description":"ElevenLabs voice id.","in":"path","name":"voiceId","required":true,"schema":{"description":"Voice id.","example":"21m00Tcm4TlvDq8ikWAM","type":"string"}},{"description":"Required stable key for metered POST retries. Reusing the same key for the same user, route, and method reuses the same credit reservation anchor.","in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"model_id":"eleven_multilingual_v2","text":"Hello from Solomon AI."},"schema":{"$ref":"#/components/schemas/VoiceTextToSpeechRequest"}}},"description":"ElevenLabs text-to-speech request body.","required":true},"responses":{"200":{"content":{"audio/mpeg":{"schema":{"format":"binary","type":"string"}}},"description":"Audio stream returned by ElevenLabs."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"402":{"$ref":"#/components/responses/402"},"502":{"$ref":"#/components/responses/502"},"503":{"$ref":"#/components/responses/503"}},"security":[{"BearerAuth":[]}],"summary":"Generate speech audio","tags":["Voice"]}},"/v1/webhooks/events":{"post":{"description":"Receives arbitrary normalized webhook events, verified via X-Webhook-Signature HMAC over X-Webhook-Timestamp plus the raw body using WEBHOOK_SIGNING_SECRET. The Unix timestamp must be within five minutes of the server clock to prevent replay. The request names the owning userId; source defaults to webhook and may be mcp, github, linear, or stripe for connector/provider gateways. Payload is sealed, and routing uses the same cloud event router as provider webhooks.","operationId":"genericWebhook","parameters":[{"description":"Unix timestamp included in the webhook signature; must be within five minutes of server time.","in":"header","name":"X-Webhook-Timestamp","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"eventType":"invoice.disputed","payload":{"customer":"Acme","invoice":"4821","reason":"pricing mismatch"},"sourceAccountId":"zapier-acme-ar","sourceEventId":"evt_123","userId":"a8dfa9b6-a7b2-46ea-982c-622a914c00e5"},"schema":{"$ref":"#/components/schemas/GenericWebhookEventRequest"}}},"description":"Generic webhook event envelope.","required":true},"responses":{"200":{"content":{"application/json":{"example":{"deduped":true,"eventId":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","routingStatus":"routed"},"schema":{"$ref":"#/components/schemas/CloudEventIngestResponse"}}},"description":"Duplicate dedupeKey: existing event returned."},"202":{"content":{"application/json":{"example":{"deduped":false,"eventId":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","routingStatus":"pending"},"schema":{"$ref":"#/components/schemas/CloudEventIngestResponse"}}},"description":"Event ingested."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"413":{"content":{"application/problem+json":{"example":{"code":"request_body_too_large","detail":"request body exceeds 327680 bytes","requestId":"req-abc123","status":413,"title":"Request Entity Too Large","type":"https://api.rowboat.dev/problems/request_body_too_large"},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Payload exceeds the configured size cap."},"500":{"$ref":"#/components/responses/500"}},"security":[{"WebhookHMAC":[]}],"summary":"Generic signed webhook event","tags":["Cloud Events"]}},"/v1/webhooks/google":{"post":{"description":"Receives Gmail Pub/Sub pushes plus Google Calendar and Drive channel notifications. Production Gmail pushes require a Google-signed OIDC bearer token with the configured audience and service-account email. Calendar and Drive use X-Goog-Channel-Token plus an exact active watch binding. The query token is retained only for local Pub/Sub mocks. Events for unresolved accounts are acknowledged with 200 and dropped.","operationId":"googleWebhook","parameters":[{"description":"Development-only shared token for local Gmail Pub/Sub mocks; production uses OIDC bearer authentication.","in":"query","name":"token","required":false,"schema":{"description":"Development webhook token.","example":"","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"message":{"data":"eyJlbWFpbEFkZHJlc3MiOiJtZUBnbWFpbC5jb20iLCJoaXN0b3J5SWQiOjk5ODg3N30=","messageId":"m1"}},"schema":{"additionalProperties":true,"description":"Pub/Sub push envelope.","type":"object"}}},"description":"Pub/Sub push envelope (Gmail). Calendar and Drive notifications carry no body.","required":false},"responses":{"200":{"description":"Acknowledged: sync handshake, duplicate, or unresolved account (dropped)."},"202":{"content":{"application/json":{"example":{"deduped":false,"eventId":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","routingStatus":"pending"},"schema":{"$ref":"#/components/schemas/CloudEventIngestResponse"}}},"description":"Event ingested."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"summary":"Google push webhook","tags":["Cloud Events"]}},"/v1/webhooks/slack":{"post":{"description":"Receives Slack Events API deliveries, verified via the X-Slack-Signature HMAC (v0:{ts}:{body} with SLACK_SIGNING_SECRET, ±5 minute replay window). Handles the url_verification handshake; event_callback deliveries for workspaces mapped to a Rowboat user are ingested, others are acknowledged and dropped.","operationId":"slackWebhook","requestBody":{"content":{"application/json":{"example":{"event":{"text":"hello","type":"message"},"event_id":"Ev001","team_id":"T0EXAMPLE","type":"event_callback"},"schema":{"additionalProperties":true,"description":"Slack event envelope.","type":"object"}}},"description":"Slack Events API envelope.","required":true},"responses":{"200":{"description":"Handshake challenge echoed, duplicate, or unmapped workspace (dropped)."},"202":{"content":{"application/json":{"example":{"deduped":false,"eventId":"0c0afab1-7f6f-4f0b-9d8e-1e58e8b0f111","routingStatus":"pending"},"schema":{"$ref":"#/components/schemas/CloudEventIngestResponse"}}},"description":"Event ingested."},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"500":{"$ref":"#/components/responses/500"}},"summary":"Slack Events API webhook","tags":["Cloud Events"]}}},"servers":[{"description":"Oppulence API","url":"https://api.oppulence.io"}],"tags":[{"description":"Health, readiness, and generated documentation endpoints.","name":"System"},{"description":"WorkOS AuthKit broker endpoints used by the desktop before it has a bearer token.","name":"Auth"},{"description":"Authenticated viewer identity, plan, and credit usage.","name":"Billing"},{"description":"Authenticated cloud mirror for desktop background task specs, artifacts, run state, JSONL events, and remote trigger queueing.","name":"Background Tasks"},{"description":"Credit-gated OpenAI-compatible text, chat, embedding, model-list, and streaming endpoints.","name":"LLM"},{"description":"Credit-gated ElevenLabs text-to-speech proxy.","name":"Voice"},{"description":"Credit-gated Exa search proxy.","name":"Search"},{"description":"Browser and desktop handoff endpoints for Google OAuth tokens.","name":"Google OAuth"},{"description":"Connector registry, OAuth start/callback, MCP token minting, and disconnect flows.","name":"Connectors"},{"description":"Shared-secret webhooks from OAuth infrastructure.","name":"Webhooks"},{"description":"Living relationship state, append-only evidence, deterministic projections, corrections, source health, and governed recommendations (RFC 036).","name":"Relationship Intelligence"},{"description":"Revenue Action Queue: relationships, evidence-backed actions, OutboundConsole policy preflight, approval, and governed execution (RFC 030).","name":"Revenue"},{"description":"Server-to-server APIs guarded by X-Internal-Secret.","name":"Internal"},{"description":"Internal admin GraphQL over the ent graph.","name":"GraphQL"}]}