{"openapi":"3.1.0","info":{"title":"OXYGEN API","version":"1.1026.33","description":"The HTTP API behind the OXYGEN web app, CLI and MCP server. Every endpoint below is one the product itself calls, generated from the API on each release.\n\n**Beta:** paths and fields can still change between releases. The [CLI](/docs/surfaces/cli) and [MCP server](/docs/surfaces/mcp) absorb those changes for you.\n\n## Authentication\n\nCreate a workspace API key in **Settings → CLI and MCP** or with `oxygen api-keys create`. Send it as `Authorization: Bearer <key>`, together with `X-Oxygen-Client-Version`: a version at or above `meta.minimum_cli_version` from any response (currently 1.1011.489). A request without it is refused with 426 `cli_update_required`.\n\n```sh\ncurl https://getoxygenagent.com/api/cli/whoami \\\n  -H \"Authorization: Bearer $OXYGEN_API_KEY\" \\\n  -H \"X-Oxygen-Client-Version: 1.1011.489\"\n```\n\n## Responses\n\nEvery response is `{ \"ok\": true, \"data\": …, \"meta\": … }` or `{ \"ok\": false, \"error\": { \"code\", \"message\", \"details\" }, \"meta\": … }`. Branch on `error.code`. Writes report `effect_outcome` and `changed`. Paid and outbound actions preview first and need explicit approval.\n\nErrors, approvals, paging and rate limits: [HTTP API guide](/docs/api)."},"servers":[{"url":"https://getoxygenagent.com"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"API keys"},{"name":"Action columns"},{"name":"Activation"},{"name":"Ads"},{"name":"Agent"},{"name":"Billing"},{"name":"Blueprints"},{"name":"Budget"},{"name":"CRM"},{"name":"Chat"},{"name":"Collab"},{"name":"Columns"},{"name":"Companies"},{"name":"Company enrichment"},{"name":"Connectors"},{"name":"Context"},{"name":"Copilot"},{"name":"Custom integrations"},{"name":"DB"},{"name":"Dashboards"},{"name":"Deliverability"},{"name":"Directory"},{"name":"Domains"},{"name":"Egress"},{"name":"Email"},{"name":"Email assets"},{"name":"Email documents"},{"name":"Enrich column"},{"name":"Enrichment"},{"name":"Feedback"},{"name":"Find"},{"name":"Home"},{"name":"Inbox"},{"name":"Integrations"},{"name":"Knowledge"},{"name":"Lead sourcing"},{"name":"Limits"},{"name":"Linkedin"},{"name":"Mailboxes"},{"name":"Managed inboxes"},{"name":"Message reviews"},{"name":"Messages"},{"name":"Migrations"},{"name":"Notetaker"},{"name":"Observability"},{"name":"Onboarding"},{"name":"Orgs"},{"name":"People"},{"name":"Pricing"},{"name":"Projects"},{"name":"Publishing"},{"name":"Recipes"},{"name":"Runs"},{"name":"Search"},{"name":"Senders"},{"name":"Sequencer"},{"name":"Sequences"},{"name":"Sessions"},{"name":"Settings"},{"name":"Signals"},{"name":"Signup leads"},{"name":"Skills"},{"name":"Sourcing"},{"name":"Spintax"},{"name":"Subscriptions"},{"name":"Supabase"},{"name":"Support"},{"name":"Suppressions"},{"name":"Table action items"},{"name":"Table action runs"},{"name":"Table ingestion runs"},{"name":"Tables"},{"name":"Tags"},{"name":"Teammates"},{"name":"Templates"},{"name":"Tools"},{"name":"UGC"},{"name":"Unibox"},{"name":"Verify"},{"name":"Visuals"},{"name":"Voice"},{"name":"Whatsapp"},{"name":"Whoami"},{"name":"Worker"},{"name":"Workflows"},{"name":"Workspace"}],"paths":{"/api/cli/action-columns/provider":{"post":{"operationId":"postActionColumnsProvider","tags":["Action columns"],"summary":"Add Provider Action Column","description":"Adds a provider action picker column: lists the provider's catalog operations as setup metadata; runs nothing until one becomes a tool column.\n\nMCP: `oxygen_action_column_add_provider`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"dryRun":{},"dry_run":{"type":"boolean","description":"Preview the column definition and operation list without creating it."},"key":{"type":"string","description":"Stable column key. Defaults to <provider>_actions.","maxLength":64},"label":{"type":"string","description":"Optional display label for the new column.","maxLength":200},"operation_filter":{"type":"array","description":"Operation, tool id, category, or tag filters. Omit for all catalog operations.","items":{"type":"string"},"maxItems":100},"provider":{"type":"string","description":"Provider id: a native @oxygen/tools provider (attio/hubspot/apollo) or a Composio toolkit id (exa/notion/gmail/slack).","minLength":1,"maxLength":80},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_action_column_add_provider"]}},"/api/cli/activation/checklist":{"get":{"operationId":"activation.checklist","tags":["Activation"],"summary":"Activation checklist","description":"Read this workspace's getting-started checklist: leads in a table, a first sequence, a connected sending account and a launched sequence, each with whether it is done and a link to do it; eligible says whether the sidebar shows it. Read-only, 0 credits.\n\nCLI: `oxygen activation checklist`.\n\nMCP: `oxygen_activation_checklist`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_activation_checklist"],"x-oxygen-cli-command":"oxygen activation checklist"}},"/api/cli/activation/state":{"get":{"operationId":"activation.state","tags":["Activation"],"summary":"Activation state","description":"Read this workspace's onboarding activation state and next available actions.\n\nMCP: `oxygen_activation_state`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_activation_state"]}},"/api/cli/ads/searches":{"get":{"operationId":"getAdsSearches","tags":["Ads"],"summary":"Saved Ads Searches","description":"List, get, save, or update a named Ads search; action=delete archives it. Call this mixed read/write tool through oxygen_capabilities_call for every action, including list and get. Saving is free and makes no provider call. Use oxygen_adyntel_ads_search to run its stored query under the preview and credit gate; use oxygen_tags_attach to change its tags.\n\nMCP: `oxygen_ads_searches`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tag","in":"query","required":false,"schema":{"type":"string","description":"List filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_ads_searches"]},"post":{"operationId":"postAdsSearches","tags":["Ads"],"summary":"Saved Ads Searches","description":"List, get, save, or update a named Ads search; action=delete archives it. Call this mixed read/write tool through oxygen_capabilities_call for every action, including list and get. Saving is free and makes no provider call. Use oxygen_adyntel_ads_search to run its stored query under the preview and credit gate; use oxygen_tags_attach to change its tags.\n\nMCP: `oxygen_ads_searches`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"company_domain":{"type":"string","description":"Required for facebook_ads, google_ads, and linkedin_ads; e.g. acme.com."},"country_code":{"type":"string","description":"Optional two-letter country code, e.g. US."},"keyword":{"type":"string","description":"Required for facebook_ad_search, linkedin_keyword_search, and tiktok_search."},"name":{"type":"string","description":"Name for the saved search; required on save and update."},"platform":{"type":"string","description":"Adyntel ad source. Domain platforms (facebook_ads, google_ads, linkedin_ads) pull a company's ads by company_domain; keyword platforms (facebook_ad_search, linkedin_keyword_search, tiktok_search) search the ad library by keyword.","enum":["facebook_ads","google_ads","linkedin_ads","facebook_ad_search","linkedin_keyword_search","tiktok_search"]},"tags":{"type":"array","items":{"type":"string"},"description":"Initial tags on save."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_ads_searches"]}},"/api/cli/ads/searches/{id}":{"get":{"operationId":"getAdsSearchesId","tags":["Ads"],"summary":"Saved Ads Searches","description":"List, get, save, or update a named Ads search; action=delete archives it. Call this mixed read/write tool through oxygen_capabilities_call for every action, including list and get. Saving is free and makes no provider call. Use oxygen_adyntel_ads_search to run its stored query under the preview and credit gate; use oxygen_tags_attach to change its tags.\n\nMCP: `oxygen_ads_searches`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_ads_searches"]},"patch":{"operationId":"patchAdsSearchesId","tags":["Ads"],"summary":"Saved Ads Searches","description":"List, get, save, or update a named Ads search; action=delete archives it. Call this mixed read/write tool through oxygen_capabilities_call for every action, including list and get. Saving is free and makes no provider call. Use oxygen_adyntel_ads_search to run its stored query under the preview and credit gate; use oxygen_tags_attach to change its tags.\n\nMCP: `oxygen_ads_searches`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"company_domain":{"type":"string","description":"Required for facebook_ads, google_ads, and linkedin_ads; e.g. acme.com."},"country_code":{"type":"string","description":"Optional two-letter country code, e.g. US."},"keyword":{"type":"string","description":"Required for facebook_ad_search, linkedin_keyword_search, and tiktok_search."},"name":{"type":"string","description":"Name for the saved search; required on save and update."},"platform":{"type":"string","description":"Adyntel ad source. Domain platforms (facebook_ads, google_ads, linkedin_ads) pull a company's ads by company_domain; keyword platforms (facebook_ad_search, linkedin_keyword_search, tiktok_search) search the ad library by keyword.","enum":["facebook_ads","google_ads","linkedin_ads","facebook_ad_search","linkedin_keyword_search","tiktok_search"]},"tags":{"type":"array","items":{"type":"string"},"description":"Initial tags on save."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_ads_searches"]},"delete":{"operationId":"deleteAdsSearchesId","tags":["Ads"],"summary":"Saved Ads Searches","description":"List, get, save, or update a named Ads search; action=delete archives it. Call this mixed read/write tool through oxygen_capabilities_call for every action, including list and get. Saving is free and makes no provider call. Use oxygen_adyntel_ads_search to run its stored query under the preview and credit gate; use oxygen_tags_attach to change its tags.\n\nMCP: `oxygen_ads_searches`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_ads_searches"]}},"/api/cli/ads/searches/{id}/tags":{"post":{"operationId":"postAdsSearchesIdTags","tags":["Ads"],"summary":"Tag a Definition","description":"Replaces workspace tags on one Signal type, saved Dashboard, runtime Agent, or saved Ads search. This is metadata only and never runs a provider.\n\nMCP: `oxygen_tags_attach`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"},"description":"The complete tag list; [] clears."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tags_attach"]}},"/api/cli/agent":{"get":{"operationId":"getAgent","tags":["Agent"],"summary":"List Built-in Agents","description":"Lists the built-in agents (your first Oxygent and the specialists) with enabled state, approval boundary, and recent runs.\n\nMCP: `oxygen_agent_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_list"]}},"/api/cli/agent/{slug}":{"get":{"operationId":"getAgentSlug","tags":["Agent"],"summary":"Get Agent","description":"Shows one agent (your first Oxygent, a specialist, or a custom agent) with its active version, approval boundary, and recent runs.\n\nMCP: `oxygen_agent_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_get"]},"patch":{"operationId":"patchAgentSlug","tags":["Agent"],"summary":"Publish Agent Version","description":"Publishes an immutable version (governed model, context, skills, tools, sandbox, limits) for a runtime agent: your first Oxygent or a custom agent. Use this to reconfigure a custom agent created with oxygen_agent_create.\n\nMCP: `oxygen_agent_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm_full_access":{"type":"boolean","description":"Required acknowledgement when tool policy mode is full."},"context_policy":{"type":"object","additionalProperties":true},"instructions":{"type":"string","description":"Durable instructions for this immutable version."},"limits":{"type":"object","additionalProperties":true},"model_policy":{"type":"object","additionalProperties":true},"sandbox_policy":{"type":"object","additionalProperties":true},"skillSlugs":{},"skill_slugs":{"type":"array","items":{"type":"string"},"maxItems":5},"tool_policy":{"type":"object","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_update"]},"delete":{"operationId":"deleteAgentSlug","tags":["Agent"],"summary":"Archive Custom Agent","description":"Archives (soft-deletes) a custom agent: its triggers stop firing and it leaves the roster, while its versions, runs, and provenance are preserved. Built-in agents cannot be archived.\n\nMCP: `oxygen_agent_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_agent_delete"]}},"/api/cli/agent/{slug}/disable":{"post":{"operationId":"postAgentSlugDisable","tags":["Agent"],"summary":"Disable Built-in Agent","description":"Disables one built-in agent (your first Oxygent or a specialist) so it stops its drafts/runs next worker tick. The notetaker keeps manual scheduling by design.\n\nMCP: `oxygen_agent_disable`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_disable"]}},"/api/cli/agent/{slug}/enable":{"post":{"operationId":"postAgentSlugEnable","tags":["Agent"],"summary":"Enable Built-in Agent","description":"Enables one built-in agent (your first Oxygent or a specialist) so it resumes its approval-gated drafts/runs. Writes only its enabled flag.\n\nMCP: `oxygen_agent_enable`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_enable"]}},"/api/cli/agent/{slug}/runs":{"post":{"operationId":"postAgentSlugRuns","tags":["Agent"],"summary":"Run Agent","description":"Starts a durable run for a runtime agent (your first Oxygent or a custom agent). Returns an inspectable run id and deep-link while the run continues on the worker.\n\nMCP: `oxygen_agent_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approve_above_default":{"type":"boolean","description":"The user's explicit approval of a max_credits above the default Agent run ceiling, for this run only. Ask the user first; a refusal with details.approval_kind=agent_ceiling_above_default names the default and the requested ceiling."},"approved":{"type":"boolean","description":"Explicit approval for managed inference up to max_credits."},"fileIds":{},"file_ids":{"type":"array","items":{"type":"string"},"maxItems":20},"goal":{"type":"string","description":"Natural-language goal for the agent."},"idempotency_key":{"type":"string","description":"Stable source key for retry deduplication."},"input":{"type":"object","additionalProperties":true,"description":"Structured input instead of goal."},"max_credits":{"type":"number","minimum":1,"description":"Hard credit ceiling for this run. Above the workspace's default Agent run ceiling (oxygen_limits_show: spend_safety_defaults.agent_run_max_total_credits) it also needs approve_above_default."},"thread_id":{"type":"string","description":"Existing persistent thread to continue."},"thread_mode":{"type":"string","enum":["isolated","persistent"],"description":"Create a persistent manual thread when thread_id is omitted."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_run"]}},"/api/cli/agent/{slug}/runs/{runId}":{"get":{"operationId":"getAgentSlugRunsRunId","tags":["Agent"],"summary":"Inspect Agent Run","description":"Reads one run of your first Oxygent or a custom Agent, plus its append-only event ledger. Use after_seq for incremental polling.\n\nMCP: `oxygen_agent_run_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}},{"name":"after_seq","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_run_get"]}},"/api/cli/agent/{slug}/runs/{runId}/approvals/{approvalId}":{"post":{"operationId":"postAgentSlugRunsRunIdApprovalsApprovalId","tags":["Agent"],"summary":"Decide Agent Approval","description":"Approves or rejects one pending capability call of your first Oxygent or a custom Agent and resumes the durable run. The approval id comes from oxygen_agent_run_get events.\n\nMCP: `oxygen_agent_approval_decide`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}},{"name":"approvalId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["approved","rejected"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_approval_decide"]}},"/api/cli/agent/{slug}/runs/{runId}/cancel":{"post":{"operationId":"postAgentSlugRunsRunIdCancel","tags":["Agent"],"summary":"Cancel Agent Run","description":"Requests checkpointed cancellation of an active run of your first Oxygent or a custom Agent.\n\nMCP: `oxygen_agent_run_cancel`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_agent_run_cancel"]}},"/api/cli/agent/{slug}/sessions":{"get":{"operationId":"agent.sessions.list","tags":["Agent"],"summary":"Agent session list","description":"List independent ongoing sessions under an Agent, including status, next check and spend.\n\nCLI: `oxygen agent session list`.\n\nMCP: `oxygen_agent_session_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_session_list"],"x-oxygen-cli-command":"oxygen agent session list"},"post":{"operationId":"agent.sessions.create","tags":["Agent"],"summary":"Agent session create","description":"Create a draft ongoing session. Explicit caps are required; review and activate separately.\n\nCLI: `oxygen agent session create`.\n\nMCP: `oxygen_agent_session_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"config":{"type":"object","additionalProperties":false,"properties":{"title":{"type":"string","minLength":1,"maxLength":160},"goal":{"type":"string","minLength":1,"maxLength":16000},"template":{"type":"string","minLength":1},"resources":{"type":"object","additionalProperties":false,"properties":{"sequences":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"tables":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"conversations":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"mailboxes":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"records":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"objects":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"knowledge":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"domains":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100}},"required":["sequences","tables","conversations","mailboxes","records","objects","knowledge","domains"]},"actions":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100,"description":"Optional standing write permissions from the template catalog. Empty means scoped reads only; template suggestions are never automatically granted."},"events":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"schedule":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string","enum":["interval","cron"],"description":"interval (default) wakes every interval_minutes; cron wakes at each cron time in timezone and needs no interval fields."},"interval_minutes":{"type":"integer","minimum":5,"description":"Default cadence in minutes; 1440 means one day."},"min_interval_minutes":{"type":"integer","minimum":5,"description":"Earliest permitted interval when the Agent requests its next check."},"max_interval_minutes":{"type":"integer","minimum":5,"maximum":525600,"description":"Latest permitted interval when the Agent requests its next check."},"cron":{"type":"string","minLength":9,"maxLength":120,"description":"Five fields, e.g. \"0 9 * * 1-5\"."},"timezone":{"type":"string","minLength":1,"maxLength":64,"description":"IANA zone for cron, e.g. Europe/Berlin."}}},"budget":{"type":"object","additionalProperties":false,"properties":{"per_run_credits":{"type":"number","minimum":0.01,"maximum":25000,"description":"Credit cap for each check, including inference and paid tools. The host reserves this full cap before starting."},"daily_credits":{"type":"number","minimum":0.01,"description":"Rolling 24-hour credit cap. Settled costs count for 24 hours; unresolved costs remain held until settled."},"lifetime_credits":{"type":"number","minimum":0.01,"description":"Optional total credit cap across all checks in this session."}},"required":["per_run_credits","daily_credits"]},"ends_at":{"type":"string","description":"Optional ISO end time."},"guided_activation":{"type":"object","additionalProperties":false,"properties":{"activation_id":{"type":"string","minLength":36,"maxLength":36},"purpose":{"type":"string","enum":["lead_scan","morning_briefing"]},"scan_policy":{"type":"object","additionalProperties":false,"properties":{"version":{"type":"integer","minimum":1,"maximum":1},"table_id":{"type":"string","minLength":1,"maxLength":160},"chat_id":{"type":"string","minLength":1,"maxLength":160},"policy_digest":{"type":"string","minLength":1,"maxLength":160},"revisions":{"type":"object","additionalProperties":false,"properties":{"configuration":{"type":"string","minLength":1,"maxLength":160},"sequence":{"type":"string","minLength":1,"maxLength":160},"audience":{"type":"string","minLength":1,"maxLength":160},"recipients":{"type":"string","minLength":1,"maxLength":160},"sender":{"type":"string","minLength":1,"maxLength":160},"copy":{"type":"string","minLength":1,"maxLength":160},"knowledge":{"type":"string","minLength":1,"maxLength":160},"schedule":{"type":"string","minLength":1,"maxLength":160},"authority":{"type":"string","minLength":1,"maxLength":160}},"required":["configuration","sequence","audience","recipients","sender","copy","knowledge","schedule","authority"]},"sources":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"source_id":{"type":"string","minLength":1,"maxLength":160},"config_digest":{"type":"string","minLength":1,"maxLength":160},"incremental_mode":{"type":"string","enum":["cursor","watermark"]},"person_key_field":{"type":"string","minLength":1,"maxLength":160}},"required":["source_id","config_digest","incremental_mode","person_key_field"]},"minItems":1,"maxItems":20},"exclude_dnc":{"type":"boolean"},"exclude_contacted":{"type":"boolean"},"review_only":{"type":"boolean"},"max_examined":{"type":"integer","minimum":1,"maximum":1000},"max_new_leads":{"type":"integer","minimum":1,"maximum":100},"max_provider_pages":{"type":"integer","minimum":1,"maximum":100},"max_provider_credits":{"type":"number","minimum":0,"maximum":25000},"max_inference_credits":{"type":"number","minimum":0,"maximum":25000}},"required":["version","table_id","chat_id","policy_digest","revisions","sources","exclude_dnc","exclude_contacted","review_only","max_examined","max_new_leads","max_provider_pages","max_provider_credits","max_inference_credits"]}},"required":["activation_id","purpose"]},"teammate_routine":{"type":"object","description":"An Oxygent routine: your chat with this Agent, which its reports post into. Only you may then start, change or message it.","additionalProperties":false,"properties":{"chat_id":{"type":"string","minLength":36,"maxLength":36},"proposal_id":{"type":"string","minLength":1,"maxLength":64},"report_policy":{"type":"string","enum":["changes_only","periodic"]}},"required":["chat_id"]}},"required":["title","goal","template","resources","actions","events","schedule","budget"]}},"required":["config"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_session_create"],"x-oxygen-cli-command":"oxygen agent session create"}},"/api/cli/agent/{slug}/sessions/{session}":{"get":{"operationId":"agent.sessions.get","tags":["Agent"],"summary":"Agent session get","description":"Read this session's configuration revision, conversation, memory, next check, approvals and budget reservations.\n\nCLI: `oxygen agent session get`.\n\nMCP: `oxygen_agent_session_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_session_get"],"x-oxygen-cli-command":"oxygen agent session get"},"patch":{"operationId":"agent.sessions.configure","tags":["Agent"],"summary":"Agent session configure","description":"Replace settings at the expected revision. Clears standing authority and pauses active work; review again before activation.\n\nCLI: `oxygen agent session configure`.\n\nMCP: `oxygen_agent_session_configure`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"revision":{"type":"integer","minimum":1},"config":{"type":"object","additionalProperties":false,"properties":{"title":{"type":"string","minLength":1,"maxLength":160},"goal":{"type":"string","minLength":1,"maxLength":16000},"template":{"type":"string","minLength":1},"resources":{"type":"object","additionalProperties":false,"properties":{"sequences":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"tables":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"conversations":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"mailboxes":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"records":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"objects":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"knowledge":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"domains":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100}},"required":["sequences","tables","conversations","mailboxes","records","objects","knowledge","domains"]},"actions":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100,"description":"Optional standing write permissions from the template catalog. Empty means scoped reads only; template suggestions are never automatically granted."},"events":{"type":"array","items":{"type":"string","minLength":1},"maxItems":100},"schedule":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string","enum":["interval","cron"],"description":"interval (default) wakes every interval_minutes; cron wakes at each cron time in timezone and needs no interval fields."},"interval_minutes":{"type":"integer","minimum":5,"description":"Default cadence in minutes; 1440 means one day."},"min_interval_minutes":{"type":"integer","minimum":5,"description":"Earliest permitted interval when the Agent requests its next check."},"max_interval_minutes":{"type":"integer","minimum":5,"maximum":525600,"description":"Latest permitted interval when the Agent requests its next check."},"cron":{"type":"string","minLength":9,"maxLength":120,"description":"Five fields, e.g. \"0 9 * * 1-5\"."},"timezone":{"type":"string","minLength":1,"maxLength":64,"description":"IANA zone for cron, e.g. Europe/Berlin."}}},"budget":{"type":"object","additionalProperties":false,"properties":{"per_run_credits":{"type":"number","minimum":0.01,"maximum":25000,"description":"Credit cap for each check, including inference and paid tools. The host reserves this full cap before starting."},"daily_credits":{"type":"number","minimum":0.01,"description":"Rolling 24-hour credit cap. Settled costs count for 24 hours; unresolved costs remain held until settled."},"lifetime_credits":{"type":"number","minimum":0.01,"description":"Optional total credit cap across all checks in this session."}},"required":["per_run_credits","daily_credits"]},"ends_at":{"type":"string","description":"Optional ISO end time."},"guided_activation":{"type":"object","additionalProperties":false,"properties":{"activation_id":{"type":"string","minLength":36,"maxLength":36},"purpose":{"type":"string","enum":["lead_scan","morning_briefing"]},"scan_policy":{"type":"object","additionalProperties":false,"properties":{"version":{"type":"integer","minimum":1,"maximum":1},"table_id":{"type":"string","minLength":1,"maxLength":160},"chat_id":{"type":"string","minLength":1,"maxLength":160},"policy_digest":{"type":"string","minLength":1,"maxLength":160},"revisions":{"type":"object","additionalProperties":false,"properties":{"configuration":{"type":"string","minLength":1,"maxLength":160},"sequence":{"type":"string","minLength":1,"maxLength":160},"audience":{"type":"string","minLength":1,"maxLength":160},"recipients":{"type":"string","minLength":1,"maxLength":160},"sender":{"type":"string","minLength":1,"maxLength":160},"copy":{"type":"string","minLength":1,"maxLength":160},"knowledge":{"type":"string","minLength":1,"maxLength":160},"schedule":{"type":"string","minLength":1,"maxLength":160},"authority":{"type":"string","minLength":1,"maxLength":160}},"required":["configuration","sequence","audience","recipients","sender","copy","knowledge","schedule","authority"]},"sources":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"source_id":{"type":"string","minLength":1,"maxLength":160},"config_digest":{"type":"string","minLength":1,"maxLength":160},"incremental_mode":{"type":"string","enum":["cursor","watermark"]},"person_key_field":{"type":"string","minLength":1,"maxLength":160}},"required":["source_id","config_digest","incremental_mode","person_key_field"]},"minItems":1,"maxItems":20},"exclude_dnc":{"type":"boolean"},"exclude_contacted":{"type":"boolean"},"review_only":{"type":"boolean"},"max_examined":{"type":"integer","minimum":1,"maximum":1000},"max_new_leads":{"type":"integer","minimum":1,"maximum":100},"max_provider_pages":{"type":"integer","minimum":1,"maximum":100},"max_provider_credits":{"type":"number","minimum":0,"maximum":25000},"max_inference_credits":{"type":"number","minimum":0,"maximum":25000}},"required":["version","table_id","chat_id","policy_digest","revisions","sources","exclude_dnc","exclude_contacted","review_only","max_examined","max_new_leads","max_provider_pages","max_provider_credits","max_inference_credits"]}},"required":["activation_id","purpose"]},"teammate_routine":{"type":"object","description":"An Oxygent routine: your chat with this Agent, which its reports post into. Only you may then start, change or message it.","additionalProperties":false,"properties":{"chat_id":{"type":"string","minLength":36,"maxLength":36},"proposal_id":{"type":"string","minLength":1,"maxLength":64},"report_policy":{"type":"string","enum":["changes_only","periodic"]}},"required":["chat_id"]}},"required":["title","goal","template","resources","actions","events","schedule","budget"]}},"required":["revision","config"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_session_configure"],"x-oxygen-cli-command":"oxygen agent session configure"}},"/api/cli/agent/{slug}/sessions/{session}/activate":{"post":{"operationId":"agent.sessions.activate","tags":["Agent"],"summary":"Agent session activate","description":"Approve the exact preview revision and activate scoped standing authority. Starts bounded inference. A cap above default_max_credits requires separate approve_above_default=true. Later settings changes require a fresh preview.\n\nCLI: `oxygen agent session activate`.\n\nMCP: `oxygen_agent_session_activate`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"revision":{"type":"integer","minimum":1},"preview_token":{"type":"string","minLength":1},"approved":{"type":"boolean"},"approve_above_default":{"type":"boolean","description":"Separately approve a per-run cap above the workspace's default Agent ceiling."}},"required":["revision","preview_token","approved"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_agent_session_activate"],"x-oxygen-cli-command":"oxygen agent session activate"}},"/api/cli/agent/{slug}/sessions/{session}/archive":{"post":{"operationId":"agent.sessions.archive","tags":["Agent"],"summary":"Agent session archive","description":"Archive this ongoing session, retaining conversation and run history.\n\nCLI: `oxygen agent session archive`.\n\nMCP: `oxygen_agent_session_archive`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_session_archive"],"x-oxygen-cli-command":"oxygen agent session archive"}},"/api/cli/agent/{slug}/sessions/{session}/complete":{"post":{"operationId":"agent.sessions.complete","tags":["Agent"],"summary":"Agent session complete","description":"Complete this ongoing session, retaining conversation and run history.\n\nCLI: `oxygen agent session complete`.\n\nMCP: `oxygen_agent_session_complete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_session_complete"],"x-oxygen-cli-command":"oxygen agent session complete"}},"/api/cli/agent/{slug}/sessions/{session}/messages":{"post":{"operationId":"agent.sessions.message","tags":["Agent"],"summary":"Agent session message","description":"Queue durable human steering. Draft chat proposes settings for review; active chat resumes the same memory. A bounded run reserves the approved per-run cap.\n\nCLI: `oxygen agent session message`.\n\nMCP: `oxygen_agent_session_message`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":16000},"idempotency_key":{"type":"string","minLength":1,"maxLength":200}},"required":["message","idempotency_key"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_agent_session_message"],"x-oxygen-cli-command":"oxygen agent session message"}},"/api/cli/agent/{slug}/sessions/{session}/pause":{"post":{"operationId":"agent.sessions.pause","tags":["Agent"],"summary":"Agent session pause","description":"Pause this ongoing session, retaining conversation and run history.\n\nCLI: `oxygen agent session pause`.\n\nMCP: `oxygen_agent_session_pause`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_session_pause"],"x-oxygen-cli-command":"oxygen agent session pause"}},"/api/cli/agent/{slug}/sessions/{session}/preview":{"post":{"operationId":"agent.sessions.preview","tags":["Agent"],"summary":"Agent session preview","description":"Preview the exact pinned Agent version, resource scope, actions, schedule and caps. Returns the revision and approval token; starts no inference.\n\nCLI: `oxygen agent session preview`.\n\nMCP: `oxygen_agent_session_preview`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_session_preview"],"x-oxygen-cli-command":"oxygen agent session preview"}},"/api/cli/agent/{slug}/sessions/{session}/resume":{"post":{"operationId":"agent.sessions.resume","tags":["Agent"],"summary":"Agent session resume","description":"Resume this ongoing session. Requires unchanged approved settings.\n\nCLI: `oxygen agent session resume`.\n\nMCP: `oxygen_agent_session_resume`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_agent_session_resume"],"x-oxygen-cli-command":"oxygen agent session resume"}},"/api/cli/agent/{slug}/sessions/{session}/run":{"post":{"operationId":"agent.sessions.run","tags":["Agent"],"summary":"Agent session run","description":"Run this active session's next check now. Guided routines require a separate bounded preview and approval; other sessions use existing caps. Refused while a check runs.\n\nCLI: `oxygen agent session run`.\n\nMCP: `oxygen_agent_session_run`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"revision":{"type":"integer","minimum":1},"preview_token":{"type":"string","minLength":1,"maxLength":160}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_agent_session_run"],"x-oxygen-cli-command":"oxygen agent session run"}},"/api/cli/agent/{slug}/sessions/{session}/webhook":{"post":{"operationId":"agent.sessions.webhook","tags":["Agent"],"summary":"Agent session webhook","description":"Create this session's webhook or rotate its secret (returned once); remove deletes it. A delivery wakes the active session within its caps; its external writes then ask first.\n\nCLI: `oxygen agent session webhook`.\n\nMCP: `oxygen_agent_session_webhook`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"remove":{"type":"boolean","description":"Delete the webhook; its URL stops accepting deliveries."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_session_webhook"],"x-oxygen-cli-command":"oxygen agent session webhook"}},"/api/cli/agent/{slug}/sessions/templates":{"get":{"operationId":"agent.sessions.templates","tags":["Agent"],"summary":"Agent session templates","description":"Discover eight ongoing Agent job templates, reviewed actions, required resources, the full config schema and a draft example. Dev only; requires a current non-client workspace member and enabled sessions. Legacy Agents remain available.\n\nCLI: `oxygen agent session templates`.\n\nMCP: `oxygen_agent_session_templates`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_session_templates"],"x-oxygen-cli-command":"oxygen agent session templates"}},"/api/cli/agent/{slug}/tags":{"post":{"operationId":"postAgentSlugTags","tags":["Agent"],"summary":"Tag a Definition","description":"Replaces workspace tags on one Signal type, saved Dashboard, runtime Agent, or saved Ads search. This is metadata only and never runs a provider.\n\nMCP: `oxygen_tags_attach`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"},"description":"The complete tag list; [] clears."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tags_attach"]}},"/api/cli/agent/{slug}/triggers":{"get":{"operationId":"getAgentSlugTriggers","tags":["Agent"],"summary":"List Agent Triggers","description":"Lists your first Oxygent's cron, event and webhook triggers: next cron time, plan slowdown, webhook URL and rate_limit; never secrets.\n\nMCP: `oxygen_agent_triggers`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_triggers"]},"post":{"operationId":"postAgentSlugTriggers","tags":["Agent"],"summary":"Create Agent Trigger","description":"Creates a cron, internal event, or signed-webhook trigger for your first Oxygent (workspace). Custom Agent trigger delivery is not exposed until identity propagation ships. Webhook creation returns its secret exactly once, plus rate_limit: the deliveries a minute its URL accepts on this plan.\n\nMCP: `oxygen_agent_trigger_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approve_above_default":{"type":"boolean","description":"The user's explicit approval of a per-delivery max_credits above the default Agent run ceiling, for every delivery of this trigger. Ask the user first."},"approved":{"type":"boolean"},"cron_expression":{"type":"string"},"event_source":{"type":"string"},"event_type":{"type":"string"},"instruction_template":{"type":"string"},"max_credits":{"type":"number","minimum":1,"description":"Standing per-delivery credit ceiling. Above the workspace's default Agent run ceiling it also needs approve_above_default."},"thread_mode":{"type":"string","enum":["isolated","persistent"]},"timezone":{"type":"string"},"type":{"type":"string","enum":["cron","event","webhook"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_trigger_create"]}},"/api/cli/agent/{slug}/triggers/{triggerId}":{"patch":{"operationId":"patchAgentSlugTriggersTriggerId","tags":["Agent"],"summary":"Set Agent Trigger Status","description":"Activates, pauses, or archives one cron, event, or webhook trigger of your first Oxygent.\n\nMCP: `oxygen_agent_trigger_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"triggerId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","paused","archived"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_trigger_set"]}},"/api/cli/agent/create":{"post":{"operationId":"postAgentCreate","tags":["Agent"],"summary":"Create Custom Agent","description":"Creates a user-defined custom Agent and publishes its first immutable version. The slug is user-minted (a lowercase letter then letters/digits/hyphens, 2-49 chars). This internal configuration write starts no run and spends no credits; manual runs stay approval-gated and credit-budgeted.\n\nMCP: `oxygen_agent_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm_full_access":{"type":"boolean","description":"Required acknowledgement when tool policy mode is full."},"context_policy":{"type":"object","additionalProperties":true},"description":{"type":"string","description":"Optional one-line description of the agent's job."},"instructions":{"type":"string","description":"Durable standing instructions for the first immutable version."},"limits":{"type":"object","additionalProperties":true},"model_policy":{"type":"object","additionalProperties":true},"name":{"type":"string","description":"Display name for the agent."},"sandbox_policy":{"type":"object","additionalProperties":true},"skillSlugs":{},"skill_slugs":{"type":"array","items":{"type":"string"},"maxItems":5},"slug":{"type":"string","description":"User-minted agent slug: a lowercase letter then letters, digits, or hyphens (2-49 chars)."},"tool_policy":{"type":"object","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_create"]}},"/api/cli/agent/custom":{"get":{"operationId":"getAgentCustom","tags":["Agent"],"summary":"List Custom Agents","description":"Lists the org's user-defined custom agents (slug, name, status, deep-link). Distinct from oxygen_agent_list, which returns the fixed built-in roster (your first Oxygent and the four specialists).\n\nMCP: `oxygen_agent_custom`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tag","in":"query","required":false,"schema":{"type":"string","description":"Optional workspace tag filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_custom"]}},"/api/cli/agent/files":{"get":{"operationId":"getAgentFiles","tags":["Agent"],"summary":"List Agent Files","description":"List tenant-owned workspace file metadata, including media, fonts and editable sources. Ready file IDs support visual compositions and Agent context; content stays tenant-scoped.\n\nMCP: `oxygen_agent_files_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_files_list"]},"post":{"operationId":"postAgentFiles","tags":["Agent"],"summary":"Create Agent Text File","description":"Stores a tenant-owned text file for Agent context or sandbox input. Inline content is capped at 1.5 MB.\n\nMCP: `oxygen_agent_file_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mime_type":{"type":"string"},"name":{"type":"string"},"text":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_agent_file_create"]}},"/api/cli/agent/runs":{"get":{"operationId":"getAgentRuns","tags":["Agent"],"summary":"List Agent Runs","description":"Recent runs across built-in and custom Agents (or one via slug), newest first, with status, credits, and deep-links.\n\nMCP: `oxygen_agent_runs`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"query","required":false,"schema":{"type":"string","description":"Optional: filter to one built-in or custom Agent."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_agent_runs"]}},"/api/cli/api-keys":{"get":{"operationId":"api_keys.list","tags":["API keys"],"summary":"API keys list","description":"List workspace API keys without revealing their tokens.\n\nMCP: `oxygen_api_keys_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_api_keys_list"]},"post":{"operationId":"api_keys.create","tags":["API keys"],"summary":"API keys create","description":"Create a workspace API key; requires the caller's personal user session. The token is returned once.\n\nMCP: `oxygen_api_keys_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"expires_at":{"type":"string","description":"ISO timestamp; omit for no expiry."},"access":{"type":"string","enum":["full","read_only"]}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_api_keys_create"]}},"/api/cli/api-keys/{id}":{"delete":{"operationId":"api_keys.revoke","tags":["API keys"],"summary":"API keys revoke","description":"Revoke a workspace API key; requires the caller's personal user session.\n\nMCP: `oxygen_api_keys_revoke`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_api_keys_revoke"]}},"/api/cli/billing/activate":{"post":{"operationId":"billing.activate","tags":["Billing"],"summary":"Billing activate","description":"Activate a trial subscription now and charge its saved payment method; administrator approval is required. An optional tier reprices the active trial in the same call.\n\nCLI: `oxygen billing activate`.\n\nMCP: `oxygen_billing_activate`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"tier":{"type":"string"}},"required":["approved"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_billing_activate"],"x-oxygen-cli-command":"oxygen billing activate"}},"/api/cli/billing/allowance":{"get":{"operationId":"billing.allowance","tags":["Billing"],"summary":"Billing allowance","description":"Inspect this workspace's recurring credit allowance and period; due plan grants or credit expiry may apply. 0 credits; reserves nothing.\n\nMCP: `oxygen_billing_allowance`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_allowance"]}},"/api/cli/billing/allowance/view":{"get":{"operationId":"billing.allowance.view","tags":["Billing"],"summary":"Billing allowance view","description":"Inspect the current-cycle allowance, billing owner and partner-bonus eligibility; due plan grants or credit expiry may apply. 0 credits; reserves nothing.\n\nCLI: `oxygen billing allowance view`.\n\nMCP: `oxygen_billing_allowance_view`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_allowance_view"],"x-oxygen-cli-command":"oxygen billing allowance view"}},"/api/cli/billing/audit":{"get":{"operationId":"getBillingAudit","tags":["Billing"],"summary":"Audit Credit Usage","description":"Summarizes where managed Oxygen credits were granted, reserved, captured, released, or spent for the active organization. Always returns spend_by_category: each spend area's credits and share, largest first. Spent is reserved minus released in the window, so it differs from totals.managed_credits_captured (oxygen_billing_usage's managed_credits_used) because of holds at the window edges and adjustments to reserved credits. Historical events retain their original credit units; windows spanning a re-denomination can mix units. Use from/to for exact date boundaries. totals.grant_credits is gross grants, excluding refunds and adjustments. byok_usage_events counts only nonzero rows unless filtered to BYOK. 0 credits; reserves nothing. Due plan grants or expiry may apply.\n\nMCP: `oxygen_billing_audit`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"nonzero","in":"query","required":false,"schema":{"type":"boolean","description":"Only include ledger rows that changed available or reserved credits. Defaults to true, except BYOK filters include zero-delta usage events."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_audit"]}},"/api/cli/billing/balance":{"get":{"operationId":"getBillingBalance","tags":["Billing"],"summary":"Get Credit Balance","description":"Compare monthly and upfront yearly prices with monthly credits; may apply due grants or expiry. Includes annual_terms, first_month_offer, subscription/next_renewal (will_charge first), committed/spendable credits, overdue renewals and warnings. Details: oxygen_billing_commitments. 0 credits.\n\nMCP: `oxygen_billing_balance`, `oxygen_tools_plan_table_batch`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_balance","oxygen_tools_plan_table_batch"]}},"/api/cli/billing/cancel":{"post":{"operationId":"postBillingCancel","tags":["Billing"],"summary":"Cancel or Resume Subscription","description":"Admin/owner only: cancel (ask why: reason) stops renewal; resume undoes; retain takes offer_id. offer previews 30% off one invoice. Confirm cancel/resume/retain. Annual commitments stay payable. No charge today.\n\nMCP: `oxygen_billing_cancel`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["cancel","resume","offer","retain"]},"comment":{"type":"string"},"offer_id":{"type":"string"},"reason":{"type":"string","enum":["too_expensive","missing_features","switched_service","unused","too_complex","low_quality","customer_service","other"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_cancel"]}},"/api/cli/billing/change":{"post":{"operationId":"postBillingChange","tags":["Billing"],"summary":"Start or Change Plan","description":"Preview via approval_url; confirm to apply/pay. Admin/owner only. Terms: oxygen_billing_balance.\n\nMCP: `oxygen_billing_change_plan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"interval":{"type":"string","enum":["month","year"],"description":"Payment cadence: month, or year for the full discounted annual charge upfront. Credits arrive monthly."},"term":{"type":"string","enum":["month","year"],"description":"Commitment; year with interval year pays the full discounted year upfront. Omit to preserve."},"tier":{"type":"string","enum":["oxygen_49","oxygen_99","oxygen_199","oxygen_499","oxygen_999","oxygen_1999"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_change_plan"]}},"/api/cli/billing/checkout":{"post":{"operationId":"billing.checkout","tags":["Billing"],"summary":"Billing checkout","description":"Checkout approval link; admin/owner for first purchase. Yearly plans charge the full discounted year upfront: use interval year, term year. Credits arrive monthly.\n\nCLI: `oxygen billing checkout`.\n\nMCP: `oxygen_billing_checkout`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string","description":"Plan key from billing balance available_plans, for example oxygen_49."},"interval":{"type":"string","enum":["month","year"],"description":"month bills monthly; year charges the full discounted year upfront."},"term":{"type":"string","enum":["month","year"],"description":"year pays the full discounted year upfront; month is the default."},"terms_version":{"type":"string","description":"Historical installment terms version; new yearly purchases use interval year."},"currency":{"type":"string","description":"Billing currency: usd (default)."},"trial":{"type":"boolean","description":"Retired compatibility option; omit for a new paid subscription."},"return_to":{"type":"string","description":"Same-origin path to return to after Checkout, for example /home."},"source":{"type":"string","description":"Optional upgrade-entry attribution; omit if unknown."},"blocked":{"type":"string","description":"Optional capability that led to the upgrade; omit if unknown."},"allow_promotion_codes":{"type":"boolean","description":"Show the promotion-code field instead of the first-month offer."}},"required":["plan"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_checkout"],"x-oxygen-cli-command":"oxygen billing checkout"}},"/api/cli/billing/commitments":{"get":{"operationId":"getBillingCommitments","tags":["Billing"],"summary":"List Fixed Credit Commitments","description":"Read current connected-resource commitments, or view=connection-prices for LinkedIn/WhatsApp/X/mailbox monthly prices and first billing timing before authorization. Default: per-kind unit price, quantity, monthly total, next due date and unpaid-renewal pauses. Read-only, 0 credits.\n\nMCP: `oxygen_billing_commitments`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["commitments","connection-prices"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_commitments"]}},"/api/cli/billing/commitments/view":{"get":{"operationId":"billing.commitments.view","tags":["Billing"],"summary":"Billing commitments view","description":"Read the complete fixed-credit commitment view and linked billing-owner display, without enumerating a child's sibling resources.\n\nCLI: `oxygen billing commitments view`.\n\nMCP: `oxygen_billing_commitments_view`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_commitments_view"],"x-oxygen-cli-command":"oxygen billing commitments view"}},"/api/cli/billing/confirm":{"post":{"operationId":"billing.confirm","tags":["Billing"],"summary":"Billing confirm","description":"Confirm a plan-change preview within 15 minutes; approved accepts payment, term and effective date. Admin or owner only.\n\nCLI: `oxygen billing confirm`.\n\nMCP: `oxygen_billing_confirm`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"approved":{"type":"boolean"}},"required":["token","approved"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_billing_confirm"],"x-oxygen-cli-command":"oxygen billing confirm"}},"/api/cli/billing/estimate":{"post":{"operationId":"postBillingEstimate","tags":["Billing"],"summary":"Estimate Monthly Cost","description":"Quote prospective enrichment, senders, X/WhatsApp, OXYGEN deliverability managed/own-key tests and an unsaved Workflow. Current plan_fit uses stored spendable balance and runway; explicit plan compares monthly allowance. Work-email ceiling, LinkedIn found/miss/declared average, Workflow step floors and unknown upper bounds stay distinct. Own-key vendor bills are separate. 0 credits, no provider calls, writes, reservations or authority.\n\nMCP: `oxygen_billing_estimate`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email_steps":{"type":"integer","minimum":0},"emailguard_byok_inboxes":{},"emailguard_byok_tests_per_inbox":{},"emailguard_inboxes":{},"emailguard_tests_per_inbox":{},"enrich":{},"enrichments":{"type":"array","items":{"type":"string"},"description":"e.g. work_email, person_enrich"},"leads_per_month":{"type":"integer","minimum":0},"linkedin_accounts":{"type":"integer","minimum":0},"linkedin_steps":{"type":"integer","minimum":0,"description":"First is an invite."},"mailboxes":{"type":"integer","minimum":0,"description":"Connected yourself."},"managed_mailboxes":{"type":"integer","minimum":0,"description":"Bought from OXYGEN."},"plan":{"type":"string","description":"Compare against this plan key instead of the workspace's."},"whatsapp_accounts":{"type":"integer","minimum":0,"maximum":1000,"description":"WhatsApp accounts; prospective quantity."},"workflow_cron":{"type":"string","description":"Five-field cron; approximate 30-day step-cost floor."},"workflow_manifest":{"type":"object","additionalProperties":true,"description":"Unsaved oxygen-workflows-v2 draft; never saved or run."},"workflow_max_credits":{"type":"number","minimum":0,"maximum":1000000000,"description":"Declared comparison ceiling; grants no authority."},"x_accounts":{"type":"integer","minimum":0,"maximum":1000,"description":"X accounts; prospective quantity."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_estimate"]}},"/api/cli/billing/invoices":{"get":{"operationId":"billing.invoices","tags":["Billing"],"summary":"Billing invoices","description":"Read this workspace's billing invoices and their hosted payment links.\n\nMCP: `oxygen_billing_invoices`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_invoices"]}},"/api/cli/billing/invoices/view":{"get":{"operationId":"billing.invoices.view","tags":["Billing"],"summary":"Billing invoices view","description":"Read the browser invoice-history projection, including exact native timestamps, amounts and signed Stripe invoice links.\n\nCLI: `oxygen billing invoices view`.\n\nMCP: `oxygen_billing_invoices_view`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_invoices_view"],"x-oxygen-cli-command":"oxygen billing invoices view"}},"/api/cli/billing/ownership":{"get":{"operationId":"billing.ownership.get","tags":["Billing"],"summary":"Billing ownership get","description":"Read the active workspace's shared billing owner, candidate owners and credit cap.\n\nCLI: `oxygen billing ownership get`.\n\nMCP: `oxygen_billing_ownership_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_ownership_get"],"x-oxygen-cli-command":"oxygen billing ownership get"}},"/api/cli/billing/portal":{"post":{"operationId":"billing.portal","tags":["Billing"],"summary":"Billing portal","description":"Create a Stripe billing-portal URL. Admin or owner only.\n\nCLI: `oxygen billing portal`.\n\nMCP: `oxygen_billing_portal`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"returnUrl":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_portal"],"x-oxygen-cli-command":"oxygen billing portal"}},"/api/cli/billing/seats":{"get":{"operationId":"getBillingSeats","tags":["Billing"],"summary":"Get Sending Seats","description":"Read sending seats, current billing-period end, monthly credit prices and connection affordability/sponsorship (null: unknown, with reason). Paying-seat coverage may be unknown. 0 credits; reserves nothing. Due grants or credit expiry may apply.\n\nMCP: `oxygen_billing_seats`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_seats"]},"post":{"operationId":"billing.seats.set","tags":["Billing"],"summary":"Billing seats set","description":"Set purchased legacy sending-seat quantity; admin or owner only. Retired seats cannot increase; reducing existing seats lowers the next renewal charge.\n\nMCP: `oxygen_billing_seats_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"seat_key":{"type":"string","enum":["linkedin","whatsapp","phone_number","email_sender"]},"quantity":{"type":"integer","minimum":0}},"required":["seat_key","quantity"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_seats_set"]}},"/api/cli/billing/summary":{"get":{"operationId":"billing.summary","tags":["Billing"],"summary":"Billing summary","description":"Read saved wallet/plan, partner bonus and sending_seats status, period-end meaning, channel capacity, prices and snapshot eligibility. No grants or expiry. Connection actions recheck eligibility; first debit may remain unknown. trialCreditGrant is a budget, not a recorded grant.\n\nCLI: `oxygen billing summary`.\n\nMCP: `oxygen_billing_summary`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_summary"],"x-oxygen-cli-command":"oxygen billing summary"}},"/api/cli/billing/topup":{"get":{"operationId":"getBillingTopup","tags":["Billing"],"summary":"Buy On-demand Credits","description":"Needs a plan: Free is refused with upgrade_required (start one with oxygen_billing_change_plan). No amount: free quote via oxygen_capabilities_call; no checkout. credits/pack: creates Stripe Checkout/billing resources; no charge until payment. Price per 100; tax may be unknown. Checkout shows final tax/total. Paid credits never expire.\n\nMCP: `oxygen_billing_topup`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_topup"]},"post":{"operationId":"postBillingTopup","tags":["Billing"],"summary":"Buy On-demand Credits","description":"Needs a plan: Free is refused with upgrade_required (start one with oxygen_billing_change_plan). No amount: free quote via oxygen_capabilities_call; no checkout. credits/pack: creates Stripe Checkout/billing resources; no charge until payment. Price per 100; tax may be unknown. Checkout shows final tax/total. Paid credits never expire.\n\nMCP: `oxygen_billing_topup`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"credits":{"type":"integer","minimum":800,"maximum":769200,"description":"Custom credit amount to buy, in 100-credit increments."},"pack":{"type":"string","enum":["10","25","100","250","1000","2000","8000","20000"],"description":"Use returned quote packs. Other IDs are legacy selections repriced at the current rate. Do not combine with credits."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_topup"]}},"/api/cli/billing/usage":{"get":{"operationId":"getBillingUsage","tags":["Billing"],"summary":"Get Credit Usage Summary","description":"Due grants/expiry may apply. Ledger default; steps, BYOK fees, seats, holds. Workspace splits; ledger ISO from/to. Shares: oxygen_billing_audit via oxygen_capabilities_call.\n\nMCP: `oxygen_billing_usage`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_billing_usage"]}},"/api/cli/billing/usage/view":{"get":{"operationId":"billing.usage.view","tags":["Billing"],"summary":"Billing usage view","description":"Credit spend over 7, 30 or 90 days by category and provider, each with its share, plus permitted linked-workspace rollups; due plan grants or credit expiry may apply. totalSpent is reserved minus released; billing usage managed_credits_used counts captured credits only. Other windows or groupings: billing audit.\n\nCLI: `oxygen billing usage view`.\n\nMCP: `oxygen_billing_usage_view`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"days","in":"query","required":false,"schema":{"type":"string","enum":["7","30","90"]}},{"name":"workspace","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_billing_usage_view"],"x-oxygen-cli-command":"oxygen billing usage view"}},"/api/cli/blueprints":{"get":{"operationId":"getBlueprints","tags":["Blueprints"],"summary":"List Blueprints","description":"Lists Oxygen blueprints — scaffolding bundles of tables, columns, prompt templates, and a workflow (seeds like account sourcing, waterfalls, ICP scoring, outbound pilots, plus workspace-saved ones). For guided GTM plays use oxygen_recipes_list. Use view=summary or names for bounded lists; follow next_cursor and describe a slug for full details.\n\nMCP: `oxygen_blueprints_list`, `oxygen_workflow_templates_search`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"include_seeds","in":"query","required":false,"schema":{"type":"boolean","description":"Include shipped seed blueprints (default true)."}},{"name":"q","in":"query","required":false,"schema":{}},{"name":"query","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Search text (matches name/slug/summary)."}},{"name":"tag","in":"query","required":false,"schema":{"type":"string","maxLength":80,"description":"Optional tag filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_blueprints_list","oxygen_workflow_templates_search"]}},"/api/cli/blueprints/apply":{"post":{"operationId":"postBlueprintsApply","tags":["Blueprints"],"summary":"Apply Blueprint","description":"Applies a blueprint as a 0-credit internal workspace write: creates the declared tables, grafts columns, upserts prompt templates, and registers the workflow as disabled. Reapplying the shipped LinkedIn monitor reuses its active tables and reports whether the prior configuration was unchanged while publishing a new disabled revision. It makes no provider call or external write and does not enable or run the workflow. Inspect preflight first; enabling or running is a separate action.\n\nMCP: `oxygen_blueprints_apply`, `oxygen_workflow_templates_apply`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"envelope":{"type":"object","description":"Full blueprint JSON envelope (the `Blueprint` type). Pass instead of slug to apply an in-memory blueprint.","additionalProperties":true},"inputs":{"type":"object","description":"Seed blueprint input parameters. For exported blueprints this is ignored.","additionalProperties":true},"slug":{"type":"string","description":"Blueprint slug, e.g. 'account-sourcing'.","maxLength":160},"table_refs":{"type":"object","description":"Mapping of blueprint table ref → existing destination table id (UUID). Use to reuse a table instead of creating a new one.","additionalProperties":{"type":"string"}},"workflow_id":{"type":"string","description":"Target an existing workflow by database UUID or manifest id/slug. The shipped LinkedIn monitor reuses its active tables and publishes a new disabled revision; an unmatched value creates a separate workflow.","maxLength":160},"workflow_name":{"type":"string","description":"Optional override for the resulting workflow name.","maxLength":240}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_blueprints_apply","oxygen_workflow_templates_apply"]}},"/api/cli/blueprints/archive":{"post":{"operationId":"postBlueprintsArchive","tags":["Blueprints"],"summary":"Archive Blueprint","description":"Archives a saved blueprint in this workspace by id or slug. Seed blueprints cannot be archived.\n\nMCP: `oxygen_blueprints_archive`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"blueprint_id":{},"blueprint_slug":{},"id":{"type":"string","description":"Saved blueprint UUID.","maxLength":80},"slug":{"type":"string","description":"Blueprint slug, e.g. 'account-sourcing'.","maxLength":160}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_blueprints_archive"]}},"/api/cli/blueprints/export":{"post":{"operationId":"postBlueprintsExport","tags":["Blueprints"],"summary":"Export Workflow As Blueprint","description":"Builds a portable blueprint envelope from an existing workflow in this workspace, packaging its tables, columns, and prompt templates. Output is JSON that can be shared and applied in another workspace via oxygen_blueprints_apply.\n\nMCP: `oxygen_blueprints_export`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"blueprint_id":{"type":"string","description":"Override the output blueprint slug (defaults to the workflow slug).","maxLength":160},"blueprint_name":{"type":"string","description":"Override the output blueprint name (defaults to the workflow name).","maxLength":240},"blueprint_summary":{"type":"string","description":"Optional summary describing what the blueprint does.","maxLength":4000},"blueprint_tags":{"type":"array","description":"Optional tags applied to the exported blueprint.","items":{"type":"string"}},"id":{},"name":{},"prompt_slugs":{"type":"array","description":"Optional explicit list of prompt template slugs to bundle.","items":{"type":"string"}},"prompts":{},"summary":{},"table_ids":{"type":"array","description":"Optional explicit list of table ids/slugs to bundle.","items":{"type":"string"}},"tables":{},"tags":{},"workflowId":{},"workflow_id":{"type":"string","description":"Workflow id or slug to export.","maxLength":160}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_blueprints_export"]}},"/api/cli/blueprints/get":{"post":{"operationId":"postBlueprintsGet","tags":["Blueprints"],"summary":"Describe Blueprint","description":"Returns a single blueprint envelope: tables it creates, columns and prompt templates it grafts, required integrations and workspace context keys, and the workflow it produces. The workflow's compiled bundle is left out (its size and sha256 are listed under omitted) unless include_bundle is true.\n\nMCP: `oxygen_blueprints_describe`, `oxygen_workflow_templates_describe`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"blueprint_slug":{},"id":{},"include_bundle":{"type":"boolean","description":"Return the full envelope including each workflow's compiled bundle (often 300k+ characters). Default false."},"slug":{"type":"string","description":"Blueprint slug, e.g. 'account-sourcing'.","maxLength":160}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_blueprints_describe","oxygen_workflow_templates_describe"]}},"/api/cli/blueprints/preflight":{"post":{"operationId":"postBlueprintsPreflight","tags":["Blueprints"],"summary":"Preflight Blueprint","description":"Checks a blueprint against this workspace: lists missing integrations, context keys, and collisions. Price-aware seeds fetch current runtime descriptor pricing and return a typed upper bound, cap scope/remediation, a uniform zero-spend contract, and the exact zero-credit disabled-install command. For a day-N reapply, workflow_id accepts the existing workflow database UUID and preflight preserves its resolved target; the shipped LinkedIn monitor reuses its active tables and apply publishes a new disabled revision. Never writes anything or calls a provider; descriptor upper bounds are distinct from exact request-shape dry runs.\n\nMCP: `oxygen_blueprints_preflight`, `oxygen_workflow_templates_preflight`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"envelope":{"type":"object","description":"Full blueprint JSON envelope (the `Blueprint` type). Pass instead of slug to apply an in-memory blueprint.","additionalProperties":true},"inputs":{"type":"object","description":"Seed blueprint input parameters. For exported blueprints this is ignored.","additionalProperties":true},"slug":{"type":"string","description":"Blueprint slug, e.g. 'account-sourcing'.","maxLength":160},"table_refs":{"type":"object","description":"Mapping of blueprint table ref → existing destination table id (UUID). Use to reuse a table instead of creating a new one.","additionalProperties":{"type":"string"}},"workflow_id":{"type":"string","description":"Reapply to an existing non-default workflow by database UUID or manifest id/slug; the exact next command preserves the resolved target. The shipped LinkedIn monitor reuses its active tables and apply publishes a new disabled revision. An unmatched value previews a separate workflow.","maxLength":160},"workflow_name":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_blueprints_preflight","oxygen_workflow_templates_preflight"]}},"/api/cli/blueprints/publish":{"post":{"operationId":"postBlueprintsPublish","tags":["Blueprints"],"summary":"Publish Blueprint to Marketplace","description":"Lists a blueprint on the public Oxygen marketplace at oxygen-agent.com/marketplace. Auto-creates a share URL if none exists. The publish-safety preview surfaces credential/PII warnings — call again with approved=true after reviewing them.\n\nMCP: `oxygen_blueprints_publish`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Set true to acknowledge the safety preview warnings and proceed."},"blueprint_slug":{},"category":{"type":"string","description":"Optional free-text category (e.g. outbound, enrichment).","maxLength":80},"kind":{"type":"string","description":"Listing kind. 'community' (default) for any workspace, 'official' for Oxygen-curated (gated to admin orgs).","enum":["community","official"]},"listing_category":{},"listing_kind":{},"slug":{"type":"string","description":"Blueprint slug, e.g. 'account-sourcing'.","maxLength":160}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_blueprints_publish"]}},"/api/cli/blueprints/save":{"post":{"operationId":"postBlueprintsSave","tags":["Blueprints"],"summary":"Save Blueprint","description":"Persists a blueprint envelope into this workspace's blueprint gallery so it can be re-applied, listed, and shared as JSON.\n\nMCP: `oxygen_blueprints_save`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"blueprint":{},"envelope":{"type":"object","description":"Full blueprint JSON envelope (the `Blueprint` type). Pass instead of slug to apply an in-memory blueprint.","additionalProperties":true},"name":{"type":"string","description":"Optional override for the stored blueprint name.","maxLength":240},"slug":{"type":"string","description":"Optional override for the stored blueprint slug.","maxLength":160},"summary":{"type":"string","description":"Optional override for the stored blueprint summary.","maxLength":4000}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_blueprints_save"]}},"/api/cli/blueprints/share":{"get":{"operationId":"getBlueprintsShare","tags":["Blueprints"],"summary":"List Blueprint Shares","description":"Lists existing public share URLs for blueprints in this workspace.\n\nMCP: `oxygen_blueprints_shares_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_blueprints_shares_list"]},"post":{"operationId":"postBlueprintsShare","tags":["Blueprints"],"summary":"Share Blueprint","description":"Creates a public share URL for a blueprint (oxygen-agent.com/b/<code>). Recipients can apply the blueprint with `oxygen blueprints apply --from-url <url>` or by pasting the URL in Claude. Disable later with oxygen_blueprints_unshare.\n\nMCP: `oxygen_blueprints_share`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the share starts enabled (default true)."},"expiresInDays":{},"expires_in_days":{"type":"number","description":"Optional expiry. Default: no expiry.","minimum":1,"maximum":3650},"slug":{"type":"string","description":"Blueprint slug, e.g. 'account-sourcing'.","maxLength":160}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_blueprints_share"]}},"/api/cli/blueprints/share/revoke":{"post":{"operationId":"postBlueprintsShareRevoke","tags":["Blueprints"],"summary":"Revoke Blueprint Share","description":"Revokes a public blueprint share URL by short code. Existing recipients will get a 404.\n\nMCP: `oxygen_blueprints_unshare`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{},"short_code":{"type":"string","description":"Share short code (the slug after /b/ in the URL).","maxLength":64}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_blueprints_unshare"]}},"/api/cli/blueprints/tags":{"post":{"operationId":"postBlueprintsTags","tags":["Blueprints"],"summary":"Tag Blueprint","description":"Replaces a saved blueprint's workspace tags (Tags primitive; see oxygen_tags_list). Whole-set: pass the full list, [] clears. Works on already-saved blueprints.\n\nMCP: `oxygen_blueprints_tag`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"blueprint":{"type":"string","description":"Blueprint slug or id."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"The full workspace tag list to set ([] clears)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_blueprints_tag"]}},"/api/cli/blueprints/unpublish":{"post":{"operationId":"postBlueprintsUnpublish","tags":["Blueprints"],"summary":"Unpublish Blueprint from Marketplace","description":"Removes a blueprint from the public marketplace. The share URL stays valid for visitors who already have it; the blueprint is only hidden from /marketplace.\n\nMCP: `oxygen_blueprints_unpublish`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"blueprint_slug":{},"slug":{"type":"string","description":"Blueprint slug, e.g. 'account-sourcing'.","maxLength":160}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_blueprints_unpublish"]}},"/api/cli/budget":{"get":{"operationId":"getBudget","tags":["Budget"],"summary":"List Budget Caps","description":"Lists the organization's standing credit caps by scope and window, plus the plan defaults that apply without one: the daily guard and per-run Agent and trigger ceilings.\n\nMCP: `oxygen_budget_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"scope","in":"query","required":false,"schema":{"type":"string","description":"Cap scope: org (whole workspace), table (a single table), workflow_trigger (one workflow trigger), or monitor (one scheduled workflow)."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by status (e.g. active). Defaults to all."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_budget_list"]},"post":{"operationId":"postBudget","tags":["Budget"],"summary":"Set Budget Cap","description":"Sets, raises, or lowers a standing credit cap (idempotent per scope+scope_id+window). hard_block stops runs at the cap; warn annotates but proceeds. Requires an admin or owner role.\n\nMCP: `oxygen_budget_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","description":"warn or hard_block. Defaults to hard_block."},"maxCredits":{},"max_credits":{"type":"number","description":"Cap in Oxygen credits; 0 only for scope=member.","minimum":0},"member":{"type":"string","description":"Member email for scope=member."},"scope":{"type":"string","description":"Cap scope: org (whole workspace), table (a single table), workflow_trigger (one workflow trigger), monitor (one scheduled workflow), or member (one person's own spend)."},"scopeId":{},"scope_id":{"type":"string","description":"Table id/slug for scope=table (other ids for other scopes). Omit for a scope-wide cap."},"table":{},"trigger":{},"window":{"type":"string","description":"Reset window: per_run, daily, or monthly."},"windowType":{},"window_type":{},"workflow":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_budget_set"]},"delete":{"operationId":"deleteBudget","tags":["Budget"],"summary":"Delete Budget Cap","description":"Deletes a standing budget policy by id. Requires an admin or owner role.\n\nMCP: `oxygen_budget_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"query","required":false,"schema":{"type":"string","description":"Budget policy id to delete."}},{"name":"policyId","in":"query","required":false,"schema":{}},{"name":"policy_id","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_budget_delete"]}},"/api/cli/chat":{"get":{"operationId":"chat.channel","tags":["Chat"],"summary":"Chat channel","description":"Dev only: read or initialize this workspace's native support channel, persistent threads, unread counts and members; optional search matches messages.\n\nCLI: `oxygen chat channel`.\n\nMCP: `oxygen_chat_channel`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"search","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_chat_channel"],"x-oxygen-cli-command":"oxygen chat channel"}},"/api/cli/chat/threads":{"get":{"operationId":"chat.threads.list","tags":["Chat"],"summary":"Chat threads list","description":"Dev only: list up to 100 recently updated support threads in this workspace. Search retained subjects and visible messages; initialized=false means no channel. Never creates a channel or marks messages read.\n\nCLI: `oxygen chat threads list`.\n\nMCP: `oxygen_chat_threads_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"search","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_chat_threads_list"],"x-oxygen-cli-command":"oxygen chat threads list"},"post":{"operationId":"chat.threads.create","tags":["Chat"],"summary":"Chat threads create","description":"Dev only: create a persistent native support thread; subject and body are customer-visible. No Plain or Slack transport.\n\nCLI: `oxygen chat threads create`.\n\nMCP: `oxygen_chat_thread_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subject":{"type":"string","minLength":1},"body":{"type":"string","minLength":1,"maxLength":20000},"idempotency_key":{"type":"string"},"context":{"type":"object","additionalProperties":true}},"required":["subject","body"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_chat_thread_create"],"x-oxygen-cli-command":"oxygen chat threads create"}},"/api/cli/chat/threads/{threadId}":{"get":{"operationId":"chat.threads.get","tags":["Chat"],"summary":"Chat threads get","description":"Dev only: read a native support thread, messages, members and release progress (none: no verified deployment, dev: verified on dev, prod: verified in production; stale means recheck). Continue message history with the returned cursor.\n\nCLI: `oxygen chat threads get`.\n\nMCP: `oxygen_chat_thread_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}},{"name":"after","in":"query","required":false,"schema":{"type":"string"}},{"name":"before","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_chat_thread_get"],"x-oxygen-cli-command":"oxygen chat threads get"},"patch":{"operationId":"chat.threads.update","tags":["Chat"],"summary":"Chat threads update","description":"Staff-only. Dev only: update native support status, assignment, urgency, fixing-agent progress or fix evidence; release status is verified separately.\n\nCLI: `oxygen chat threads update`.\n\nMCP: `oxygen_chat_thread_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["todo","snoozed","done"]},"waiting_for_customer":{"type":"boolean"},"snoozed_until":{"oneOf":[{"type":"string"},{"type":"null"}]},"assignee_email":{"oneOf":[{"type":"string"},{"type":"null"}]},"priority":{"type":"string","enum":["urgent","high","normal","low"]},"agent":{"oneOf":[{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"stage":{"type":"string","enum":["investigating","fixing","testing","awaiting_release","needs_human","completed"]},"summary":{"oneOf":[{"type":"string"},{"type":"null"}]},"session_url":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","stage"]},{"type":"null"}]},"release":{"type":"object","additionalProperties":false,"properties":{"fix_sha":{"oneOf":[{"type":"string"},{"type":"null"}]},"pr_url":{"oneOf":[{"type":"string"},{"type":"null"}]},"required_roles":{"type":"array","items":{"type":"string"}}}}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_chat_thread_update"],"x-oxygen-cli-command":"oxygen chat threads update"}},"/api/cli/chat/threads/{threadId}/files":{"post":{"operationId":"chat.files.upload","tags":["Chat"],"summary":"Chat files upload","description":"Dev only: upload a file into a native support thread; attach the returned ID in a reply. CLI accepts --file; MCP accepts data_base64.\n\nCLI: `oxygen chat files upload`.\n\nMCP: `oxygen_chat_file_upload`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"content_type":{"type":"string","minLength":1},"data_base64":{"type":"string","minLength":1}},"required":["name","content_type","data_base64"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_chat_file_upload"],"x-oxygen-cli-command":"oxygen chat files upload"}},"/api/cli/chat/threads/{threadId}/files/{fileId}":{"get":{"operationId":"chat.files.get","tags":["Chat"],"summary":"Chat files get","description":"Dev only: download exact bytes of a file in an authorized native support thread. CLI requires --output; MCP returns an authenticated file resource.\n\nCLI: `oxygen chat files get`.\n\nMCP: `oxygen_chat_file_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}},{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_chat_file_get"],"x-oxygen-cli-command":"oxygen chat files get"}},"/api/cli/chat/threads/{threadId}/messages":{"post":{"operationId":"chat.threads.reply","tags":["Chat"],"summary":"Chat threads reply","description":"Dev only: reply in a native support thread with uploaded attachment IDs and member mentions. Public by default; internal notes require staff.\n\nCLI: `oxygen chat threads reply`.\n\nMCP: `oxygen_chat_thread_reply`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","maxLength":20000},"attachments":{"type":"array","items":{"type":"string"}},"mentions":{"type":"array","items":{"type":"string"}},"visibility":{"type":"string","enum":["public","internal"],"description":"Public replies are customer-visible; internal notes require staff."},"idempotency_key":{"type":"string"}},"required":["body"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_chat_thread_reply"],"x-oxygen-cli-command":"oxygen chat threads reply"}},"/api/cli/chat/threads/{threadId}/read":{"post":{"operationId":"chat.threads.read","tags":["Chat"],"summary":"Chat threads read","description":"Dev only: mark a native support thread read through the viewed cursor; omit cursor to mark all currently visible messages.\n\nCLI: `oxygen chat threads read`.\n\nMCP: `oxygen_chat_thread_read`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cursor":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_chat_thread_read"],"x-oxygen-cli-command":"oxygen chat threads read"}},"/api/cli/chat/threads/{threadId}/release-check":{"post":{"operationId":"chat.release_check","tags":["Chat"],"summary":"Chat release check","description":"Staff-only. Dev only: verify whether the thread's fix is deployed to dev or production, preserving stale evidence when verification is unavailable.\n\nCLI: `oxygen chat release-check`.\n\nMCP: `oxygen_chat_release_check`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_chat_release_check"],"x-oxygen-cli-command":"oxygen chat release-check"}},"/api/cli/collab/comments/{commentId}":{"patch":{"operationId":"comments.edit","tags":["Collab"],"summary":"Comments edit","description":"Edit your own internal workspace comment; records the edit time.\n\nMCP: `oxygen_comments_edit`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string"}},"required":["body"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_comments_edit"]},"delete":{"operationId":"comments.delete","tags":["Collab"],"summary":"Comments delete","description":"Retract your own internal workspace comment while retaining its audit trail.\n\nMCP: `oxygen_comments_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_comments_delete"]}},"/api/cli/collab/gates":{"get":{"operationId":"collaboration.gates.list","tags":["Collab"],"summary":"Approvals gate list","description":"Read this workspace's approval gates, optionally for one exact subject.\n\nMCP: `oxygen_approval_gates_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"subject","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_approval_gates_list"]},"post":{"operationId":"postCollabGates","tags":["Collab"],"summary":"Require or Release an Approval Gate","description":"Turns the HARD gate on or off — the policy that makes an approval blocking rather than advisory. Scope it to one object with `on`, or to every object of a kind with `subject_kind` (the workspace default). launch gates a sequence (approve before a sequence starts sending live); signoff gates a table (approve the table's rows before they are worked). While required and unapproved, the owning primitive's LIVE path refuses with approval_required; previews and dry runs stay open, so a client can always inspect what they are being asked to approve. ADMIN ONLY, deliberately: a member who can switch the gate off at will is not a gate. Idempotent upsert. Free: internal write, no credits. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_approvals_gate_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"gate_kind":{"type":"string","enum":["launch","signoff"],"description":"Which gate to require or release."},"required":{"type":"boolean","description":"true blocks the live action until an approved request exists; false releases it."},"subject_id":{},"subject_kind":{"type":"string","enum":["knowledge_page","publishing_post","sequence","table","workflow","recipe","conversation","mailbox","sender","record","domain","project","sender_profile","voice_number","signal_type","dashboard","agent","ad_search_collection"],"description":"Workspace default for every object of this kind. Use instead of `on`, not with it."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_approvals_gate_set"]}},"/api/cli/collab/inbox":{"get":{"operationId":"getCollabInbox","tags":["Collab"],"summary":"What Is Waiting on Me","description":"What this user must answer: approval requests assigned to them and still pending, plus open comment threads that name them — newest first, each with the exact command that answers it. This is the first call for a client login. Read-only and free. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_approvals_inbox`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"number","minimum":1,"maximum":200,"description":"Items per section. Default 50."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_approvals_inbox"]}},"/api/cli/collab/members":{"get":{"operationId":"collaboration.members.list","tags":["Collab"],"summary":"Members list","description":"Read workspace member roles, with Clerk profiles and pending invitations. Free.\n\nMCP: `oxygen_workspace_members_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_members_list"]}},"/api/cli/collab/members/role":{"post":{"operationId":"members.role","tags":["Collab"],"summary":"Members role","description":"Set a member's workspace role, held in Clerk: admin, member, rep (sales rep), viewer or client; null lifts a restricted role. Admin only; you cannot change your own role. May read pending Clerk invitations; sends no invitation. Free.\n\nMCP: `oxygen_members_role_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"role":{"oneOf":[{"type":"string","enum":["admin","member","rep","viewer","client"]},{"type":"null"}]}},"required":["email","role"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_members_role_set"]}},"/api/cli/collab/members/workspace-role":{"post":{"operationId":"members.workspace_role","tags":["Collab"],"summary":"Orgs member role","description":"Change a member's workspace role in Clerk; admin only, with self-role and last-administrator protection. Free.\n\nMCP: `oxygen_members_workspace_role_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"role":{"type":"string","enum":["admin","member"]}},"required":["email","role"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_members_workspace_role_set"]}},"/api/cli/collab/requests":{"get":{"operationId":"getCollabRequests","tags":["Collab"],"summary":"List Approval Requests","description":"Approval requests across the workspace — who asked, who must decide, the decision and its note, and whether the request opens its gate. Filter by status, by subject, or with assigned_to_me=true; pass `request_id` for ONE request when that id is all you have (a notification email, a /collab/approvals/<id> link), which also reports whether it has lapsed past its expiry and can no longer be decided. Read `opens_gate` rather than inferring it from status: changes_requested is decided but does NOT open a gate. Read-only and free. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_approvals_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"assigned_to_me","in":"query","required":false,"schema":{"type":"boolean","description":"Only requests this user must decide."}},{"name":"limit","in":"query","required":false,"schema":{"type":"number","minimum":1,"maximum":200,"description":"Requests to return. Default 50."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","pattern":"^\\s*(?:pending|approved|changes_requested|rejected|cancelled|expired|all)?\\s*(?:,\\s*(?:pending|approved|changes_requested|rejected|cancelled|expired|all)?\\s*)*$","description":"CSV: pending, approved, changes_requested, rejected, cancelled, expired. Whitespace and empty entries are ignored. Omit, or use all alone, for every status."}},{"name":"subject","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_approvals_list"]},"post":{"operationId":"postCollabRequests","tags":["Collab"],"summary":"Request an Approval","description":"Asks named workspace members to decide before work goes live — the client's documented go/no-go. launch gates a sequence (approve before a sequence starts sending live); signoff gates a table (approve the table's rows before they are worked). Assignees are EMAILS and must already be members: a non-member is a named 400, never a silent drop, because a request nobody can decide is only noticed when the campaign is still sitting there the next morning. They must also be someone OTHER than the caller — assigning yourself is a 400 (collab_self_assignment_forbidden), including in a mixed list, since a request the requester can answer is not a second-party approval. Creating a request BLOCKS NOTHING by itself — the hard gate is a separate admin policy (oxygen_approvals_gate_set) enforced by the owning primitive's own route. Free: internal write, no credits; assignees get a notification, not an external send. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_approvals_request`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"assignees":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10,"description":"Emails of the workspace members asked to decide. Never the caller's own address."},"body":{"type":"string","maxLength":10000,"description":"What you want them to check."},"expires_in_hours":{"type":"number","minimum":1,"description":"Auto-expire an undecided request after this many hours. An expired request does NOT open the gate."},"gate_kind":{"type":"string","enum":["launch","signoff"],"description":"Which gate this request answers."},"subject_id":{},"subject_kind":{},"subject_path":{},"title":{"type":"string","maxLength":200,"description":"Defaults to the gate's meaning."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_approvals_request"]}},"/api/cli/collab/requests/{requestId}":{"get":{"operationId":"getCollabRequestsRequestId","tags":["Collab"],"summary":"List Approval Requests","description":"Approval requests across the workspace — who asked, who must decide, the decision and its note, and whether the request opens its gate. Filter by status, by subject, or with assigned_to_me=true; pass `request_id` for ONE request when that id is all you have (a notification email, a /collab/approvals/<id> link), which also reports whether it has lapsed past its expiry and can no longer be decided. Read `opens_gate` rather than inferring it from status: changes_requested is decided but does NOT open a gate. Read-only and free. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_approvals_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"requestId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_approvals_list"]}},"/api/cli/collab/requests/{requestId}/cancel":{"post":{"operationId":"approvals.cancel","tags":["Collab"],"summary":"Approvals cancel","description":"Withdraw an approval request you created; grants no approval.\n\nMCP: `oxygen_approvals_cancel`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"requestId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_approvals_cancel"]}},"/api/cli/collab/requests/{requestId}/decide":{"post":{"operationId":"postCollabRequestsRequestIdDecide","tags":["Collab"],"summary":"Decide an Approval Request","description":"Answers one pending request: approve, reject, or changes_requested. ONLY approve opens a gate — changes_requested is a real decision that ends the wait and still leaves the work blocked, so never read it as \"approved with notes\". Assignees decide; a workspace admin may decide on the workspace's behalf; the requester cannot decide their own request (withdraw it with `oxygen approvals cancel <id>` on the CLI instead). Replaying the same decision returns the stored answer with already=true; a different one on a decided request is a clean 409. Free: internal write, no credits. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_approvals_decide`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"requestId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["approve","reject","changes_requested"],"description":"approve opens the gate; reject and changes_requested do not."},"note":{"type":"string","maxLength":2000,"description":"Why. Quoted back to the requester on every later gate check."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_approvals_decide"]}},"/api/cli/collab/threads":{"get":{"operationId":"getCollabThreads","tags":["Collab"],"summary":"Read Comment Threads","description":"Every internal comment thread on one workspace object, with its replies, authors, mentions, and resolution state. Commentable kinds: knowledge pages, publishing posts, sequences, tables, workflows, recipes, conversations, mailboxes, sender accounts, CRM records, sending domains, projects, sender profiles, phone numbers, signal types, dashboards, agents, and saved Ads searches. Defaults to OPEN threads — pass status to see resolved ones. `path` scopes the read to one table row or cell. Pass `thread_id` instead of `on` when all you have is an id out of a notification email or a /collab/threads/<id> link: same payload, that one thread. This is the conversation ABOUT the object; the object itself is read through its own primitive's tools. Not public post comments (oxygen_publishing_comments). Read-only and free. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_comments_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"number","minimum":1,"maximum":200,"description":"Threads to return. Default 50."}},{"name":"path","in":"query","required":false,"schema":{"type":"string","description":"Narrow to a sub-object of a table: \"row:<rowId>\" for one row, \"row:<rowId>#<columnKey>\" for one cell, or \"column:<columnKey>\" for one column."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","resolved","all"],"description":"Default open."}},{"name":"subject","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_comments_list"]},"post":{"operationId":"postCollabThreads","tags":["Collab"],"summary":"Comment on a Workspace Object","description":"Opens a comment thread on one workspace object, or replies inside an existing one — the review conversation an agency has with its client, kept next to the work instead of in a Google Doc. Pass `on` to start a thread, or `thread_id` to reply in one; `path` scopes it to a single table row or cell. An `@email` in the body notifies that workspace member (so does `mentions`); an address that is not a member stays plain text. INTERNAL ONLY — these are Oxygen comments between workspace members, never public comments on a published post (that is oxygen_publishing_comments, whose approve_reply posts to LinkedIn). Free: internal write, no credits, nothing sent externally. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_comments_add`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000,"description":"The comment. Kept verbatim — Markdown and quoted text survive."},"mentions":{"type":"array","items":{"type":"string"},"maxItems":25,"description":"Workspace member emails to notify. `@email` written in the body notifies them too — this field is for addresses the prose does not name."},"subject_id":{},"subject_kind":{},"subject_path":{},"title":{"type":"string","maxLength":200,"description":"Optional heading for a NEW thread. Rejected when replying."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_comments_add"]}},"/api/cli/collab/threads/{threadId}":{"get":{"operationId":"getCollabThreadsThreadId","tags":["Collab"],"summary":"Read Comment Threads","description":"Every internal comment thread on one workspace object, with its replies, authors, mentions, and resolution state. Commentable kinds: knowledge pages, publishing posts, sequences, tables, workflows, recipes, conversations, mailboxes, sender accounts, CRM records, sending domains, projects, sender profiles, phone numbers, signal types, dashboards, agents, and saved Ads searches. Defaults to OPEN threads — pass status to see resolved ones. `path` scopes the read to one table row or cell. Pass `thread_id` instead of `on` when all you have is an id out of a notification email or a /collab/threads/<id> link: same payload, that one thread. This is the conversation ABOUT the object; the object itself is read through its own primitive's tools. Not public post comments (oxygen_publishing_comments). Read-only and free. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_comments_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_comments_list"]}},"/api/cli/collab/threads/{threadId}/comments":{"post":{"operationId":"postCollabThreadsThreadIdComments","tags":["Collab"],"summary":"Comment on a Workspace Object","description":"Opens a comment thread on one workspace object, or replies inside an existing one — the review conversation an agency has with its client, kept next to the work instead of in a Google Doc. Pass `on` to start a thread, or `thread_id` to reply in one; `path` scopes it to a single table row or cell. An `@email` in the body notifies that workspace member (so does `mentions`); an address that is not a member stays plain text. INTERNAL ONLY — these are Oxygen comments between workspace members, never public comments on a published post (that is oxygen_publishing_comments, whose approve_reply posts to LinkedIn). Free: internal write, no credits, nothing sent externally. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_comments_add`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000,"description":"The comment. Kept verbatim — Markdown and quoted text survive."},"mentions":{"type":"array","items":{"type":"string"},"maxItems":25,"description":"Workspace member emails to notify. `@email` written in the body notifies them too — this field is for addresses the prose does not name."},"parent_comment_id":{"type":"string","description":"Nest the reply under one comment of that thread. Requires thread_id."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_comments_add"]}},"/api/cli/collab/threads/{threadId}/resolve":{"post":{"operationId":"postCollabThreadsThreadIdResolve","tags":["Collab"],"summary":"Resolve or Reopen a Thread","description":"Marks one comment thread resolved, or reopens it with reopen=true. Idempotent both ways: re-resolving keeps the original resolver and timestamp. Any workspace member may resolve — resolution is a conversation state, NOT consent. It approves nothing and opens no gate; a client's go/no-go is oxygen_approvals_decide. Free: internal write, no credits. BETA: /collab is not in the web sidebar; open it by URL or a notification link.\n\nMCP: `oxygen_comments_resolve`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"resolved":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_comments_resolve"]}},"/api/cli/columns/rerun":{"post":{"operationId":"postColumnsRerun","tags":["Columns"],"summary":"Re-run AI Column for One Row","description":"Re-run one AI cell. Preview with dry_run=true, then pass max_credits; from_review_id threads prior feedback.\n\nMCP: `oxygen_columns_rerun_cell`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string","description":"Column id or key."},"dry_run":{"type":"boolean","description":"Preview the single-row credit estimate and posture without spending credits or writing a review."},"from_review_id":{"type":"string","description":"Optional prior message_review id whose feedback to honor."},"max_credits":{"type":"number","minimum":0,"description":"Live cap from the preview."},"row_id":{"type":"string","description":"Row UUID."},"table":{"type":"string","description":"Table id or slug."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_columns_rerun_cell"]}},"/api/cli/companies/search/plan":{"post":{"operationId":"postCompaniesSearchPlan","tags":["Companies"],"summary":"Plan Company Search","description":"The canonical company-search entrypoint for a prompt or nonempty filters. Compiles a prompt or filters into provider routes, table columns, gates, credit/match estimates, filter coverage, and workspace context. Use here instead of oxygen_search_*, oxygen_sourcing_plan or oxygen_lead_sourcing_plan.\nCOST: free (no paid provider calls; with estimate=true it runs at most ONE free zero-credit count probe).\nFILTERS: pass typed `filters` (ISO alpha-2 countries, funding stages, employee/revenue/founded ranges, technologies, hiring). extracted_filters.unparsed_constraint_hints reports unparsed constraints; per-route filter_application reports applied/dropped filters.\nFOLLOW-UP: _plan -> _run (dry_run) -> _run (live, approved=true, max_credits) -> oxygen_table_ingestions_wait -> oxygen_tables_preview.\n\nMCP: `oxygen_companies_search_plan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"estimate":{"type":"boolean","description":"When true (default false), free server-side preflight resolves canonical filter values and runs at most one zero-credit count probe. Results: preflight_resolution and estimated_match_count."},"filters":{"type":"object","description":"Typed company-search filters. Explicit filters merge OVER filters extracted from the prompt (explicit wins per path). All fields optional; an empty object means no constraints.","additionalProperties":false,"properties":{"names":{"type":"object","description":"Company names to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"domains":{"type":"object","description":"Company domains to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"lookalike_domains":{"type":"array","description":"Seed domains to find lookalike companies.","items":{"type":"string"}},"industries":{"type":"object","description":"Industries to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"keywords":{"type":"object","description":"Free-text keywords to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"employee_count":{"type":"object","description":"Live employee count range. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"employee_range":{"type":"array","description":"Self-reported size bands (51-200); can lag the live count.","items":{"type":"string"}},"founded_year":{"type":"object","description":"Founded-year range (e.g. 2015). Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"company_types":{"type":"object","description":"Company types to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"revenue_usd":{"type":"object","description":"Annual revenue range in USD. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"geo":{"type":"object","description":"Geographic constraints (headquarters).","additionalProperties":false,"properties":{"countries":{"type":"array","description":"ISO 3166-1 alpha-2 country codes, uppercase (e.g. US, DE, GB).","items":{"type":"string"}},"regions":{"type":"array","description":"Regions or sales territories (e.g. Europe, DACH, EMEA, NA).","items":{"type":"string"}},"cities":{"type":"object","description":"Cities to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"states":{"type":"object","description":"HQ states or regions to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}}}},"funding":{"type":"object","description":"Funding constraints.","additionalProperties":false,"properties":{"stages":{"type":"array","description":"Funding stages.","items":{"type":"string","enum":["pre_seed","seed","series_a","series_b","series_c","series_d","series_e_plus","growth","private_equity","debt","ipo","acquired"]}},"latest_amount_usd":{"type":"object","description":"Latest funding round amount range in USD. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"total_amount_usd":{"type":"object","description":"Total funding raised range in USD. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"raised_after":{"type":"string","description":"Latest round raised on or after this date (YYYY-MM-DD)."},"raised_before":{"type":"string","description":"Latest round raised on or before this date (YYYY-MM-DD)."}}},"technologies":{"type":"object","description":"Technologies used to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"hiring":{"type":"object","description":"Open-role constraints (intent hiring: one row per hiring company + matched_jobs).","additionalProperties":false,"properties":{"job_titles":{"type":"array","description":"Open-role titles.","items":{"type":"string"}},"exclude_job_titles":{"type":"array","description":"Titles to exclude.","items":{"type":"string"}},"description_keywords":{"type":"object","description":"Posting description keywords to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"theme_keywords":{"type":"object","description":"Theme keywords (title, description, skills) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"fields":{"type":"object","description":"Professional field, free-form to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"seniorities":{"type":"object","description":"Experience bands 0-2, 2-5, 5-10, 10+ to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"employment_types":{"type":"object","description":"FULL_TIME, PART_TIME, CONTRACTOR, TEMPORARY, INTERN, VOLUNTEER, PER_DIEM, OTHER to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"work_arrangements":{"type":"object","description":"On-site, Hybrid, Remote OK, Remote Solely to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"job_locations":{"type":"array","description":"Open-role cities.","items":{"type":"string"}},"exclude_job_locations":{"type":"array","description":"Cities to exclude.","items":{"type":"string"}},"job_countries":{"type":"object","description":"Open-role ISO alpha-2 countries; defaults to geo.countries to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"min_open_jobs":{"type":"number","description":"Minimum matching roles per company (max 25)."},"posted_after":{"type":"string","description":"Jobs posted on or after this date (YYYY-MM-DD)."},"last_days":{"type":"number","description":"Posted in the last N days (1-3650); wins over posted_after."},"agencies":{"type":"string","enum":["exclude","include","only"],"description":"Staffing agencies; default exclude."}}},"native_filters":{"type":"object","additionalProperties":true}}},"materialize_preview":{"type":"boolean","description":"Creates a route-plan table, not company results. Use oxygen_companies_search_preview for free company rows."},"prompt":{"type":"string","description":"Optional with nonempty filters or native_filters; blank uses the API's filter-derived prompt.","minLength":0,"maxLength":20000},"source_intent":{"type":"string","description":"Optional intent override: sizing, structured, lookalike, technology, hiring, local, known_source, concept, web, url, or fallback."},"target_count":{"type":"number","description":"Desired company count for routing and estimates. Maximum 50,000 per plan; larger populations require segmented plans.","minimum":1,"maximum":50000}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_companies_search_plan"]}},"/api/cli/companies/search/preview":{"get":{"operationId":"getCompaniesSearchPreview","tags":["Companies"],"summary":"Preview Company Search","description":"Filters or preview: 0 Oxygen credits; Maps: paid Serper request on Oxygen's account; Maps dry_run makes no supplier call. view=full: raw_source. company_search:50; hiring:50 jobs/exact total; google_maps:20. oxygen_companies_search_run: source+source_filters; dry_run first.\n\nMCP: `oxygen_companies_search_preview`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"filters","in":"query","required":false,"schema":{"type":"object","description":"Native fields; action=filters lists keys. Google Maps requires q, placeId or cid. Other sources accept {} for all results.","additionalProperties":true}},{"name":"source","in":"query","required":false,"schema":{"type":"string","enum":["company_search","hiring","google_maps"],"description":"Defaults to company_search."}},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["compact","full"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_companies_search_preview"]},"post":{"operationId":"postCompaniesSearchPreview","tags":["Companies"],"summary":"Preview Company Search","description":"Filters or preview: 0 Oxygen credits; Maps: paid Serper request on Oxygen's account; Maps dry_run makes no supplier call. view=full: raw_source. company_search:50; hiring:50 jobs/exact total; google_maps:20. oxygen_companies_search_run: source+source_filters; dry_run first.\n\nMCP: `oxygen_companies_search_preview`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"filters":{"type":"object","description":"Native fields; action=filters lists keys. Google Maps requires q, placeId or cid. Other sources accept {} for all results.","additionalProperties":true},"source":{"type":"string","enum":["company_search","hiring","google_maps"],"description":"Defaults to company_search."},"view":{"type":"string","enum":["compact","full"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_companies_search_preview"]}},"/api/cli/companies/search/run":{"post":{"operationId":"postCompaniesSearchRun","tags":["Companies"],"summary":"Run Company Search","description":"Dry-runs or queues company sourcing into a Table. Use source=company_search|hiring|google_maps + source_filters from the free preview, or a prompt/plan from oxygen_companies_search_plan.\nCOST: dry_run is free; live requires approval and max_credits. target_count sets pages; max_credits caps them (auto_paged). Provider preflight must pass.\nFILTERS: prompt filters use the plan schema; native source_filters use preview metadata.\nTABLE: omit it, or match `output_columns`.\nNEXT: dry_run -> approved live -> oxygen_table_ingestions_wait -> oxygen_tables_preview.\n\nMCP: `oxygen_companies_search_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required for live runs after inspecting dry-run output."},"estimate":{"type":"boolean","description":"When true (default false), free server-side preflight resolves canonical filter values and runs at most one zero-credit count probe. Results: preflight_resolution and estimated_match_count."},"filters":{"type":"object","description":"Typed company-search filters. Explicit filters merge OVER filters extracted from the prompt (explicit wins per path). All fields optional; an empty object means no constraints.","additionalProperties":false,"properties":{"names":{"type":"object","description":"Company names to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"domains":{"type":"object","description":"Company domains to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"lookalike_domains":{"type":"array","description":"Seed domains to find lookalike companies.","items":{"type":"string"}},"industries":{"type":"object","description":"Industries to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"keywords":{"type":"object","description":"Free-text keywords to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"employee_count":{"type":"object","description":"Live employee count range. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"employee_range":{"type":"array","description":"Self-reported size bands (51-200); can lag the live count.","items":{"type":"string"}},"founded_year":{"type":"object","description":"Founded-year range (e.g. 2015). Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"company_types":{"type":"object","description":"Company types to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"revenue_usd":{"type":"object","description":"Annual revenue range in USD. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"geo":{"type":"object","description":"Geographic constraints (headquarters).","additionalProperties":false,"properties":{"countries":{"type":"array","description":"ISO 3166-1 alpha-2 country codes, uppercase (e.g. US, DE, GB).","items":{"type":"string"}},"regions":{"type":"array","description":"Regions or sales territories (e.g. Europe, DACH, EMEA, NA).","items":{"type":"string"}},"cities":{"type":"object","description":"Cities to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"states":{"type":"object","description":"HQ states or regions to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}}}},"funding":{"type":"object","description":"Funding constraints.","additionalProperties":false,"properties":{"stages":{"type":"array","description":"Funding stages.","items":{"type":"string","enum":["pre_seed","seed","series_a","series_b","series_c","series_d","series_e_plus","growth","private_equity","debt","ipo","acquired"]}},"latest_amount_usd":{"type":"object","description":"Latest funding round amount range in USD. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"total_amount_usd":{"type":"object","description":"Total funding raised range in USD. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"raised_after":{"type":"string","description":"Latest round raised on or after this date (YYYY-MM-DD)."},"raised_before":{"type":"string","description":"Latest round raised on or before this date (YYYY-MM-DD)."}}},"technologies":{"type":"object","description":"Technologies used to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"hiring":{"type":"object","description":"Open-role constraints (intent hiring: one row per hiring company + matched_jobs).","additionalProperties":false,"properties":{"job_titles":{"type":"array","description":"Open-role titles.","items":{"type":"string"}},"exclude_job_titles":{"type":"array","description":"Titles to exclude.","items":{"type":"string"}},"description_keywords":{"type":"object","description":"Posting description keywords to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"theme_keywords":{"type":"object","description":"Theme keywords (title, description, skills) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"fields":{"type":"object","description":"Professional field, free-form to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"seniorities":{"type":"object","description":"Experience bands 0-2, 2-5, 5-10, 10+ to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"employment_types":{"type":"object","description":"FULL_TIME, PART_TIME, CONTRACTOR, TEMPORARY, INTERN, VOLUNTEER, PER_DIEM, OTHER to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"work_arrangements":{"type":"object","description":"On-site, Hybrid, Remote OK, Remote Solely to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"job_locations":{"type":"array","description":"Open-role cities.","items":{"type":"string"}},"exclude_job_locations":{"type":"array","description":"Cities to exclude.","items":{"type":"string"}},"job_countries":{"type":"object","description":"Open-role ISO alpha-2 countries; defaults to geo.countries to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"min_open_jobs":{"type":"number","description":"Minimum matching roles per company (max 25)."},"posted_after":{"type":"string","description":"Jobs posted on or after this date (YYYY-MM-DD)."},"last_days":{"type":"number","description":"Posted in the last N days (1-3650); wins over posted_after."},"agencies":{"type":"string","enum":["exclude","include","only"],"description":"Staffing agencies; default exclude."}}},"native_filters":{"type":"object","additionalProperties":true}}},"max_credits":{"type":"number","description":"Required credit ceiling for live runs.","minimum":0},"max_pages":{"type":"number","description":"Maximum provider pages to ingest. If omitted, Oxygen auto-computes it from target_count (see auto_paged).","minimum":1},"mode":{"type":"string","description":"dry_run or live. Defaults to dry_run."},"native_filters":{"type":"object","additionalProperties":true},"plan":{"type":"object","description":"Full company plan with routes; an id alone is not a retrievable plan reference. Or preview with prompt + identical filters.","required":["id","source_prompt","recommended_route_id","routes"],"properties":{"id":{"type":"string"},"source_prompt":{"type":"string"},"recommended_route_id":{"type":"string"},"routes":{"type":"array","items":{"type":"object","additionalProperties":true}}},"additionalProperties":true},"project":{"type":"string","description":"Folder id or slug for the created table; ignored with `table`.","maxLength":200},"prompt":{"type":"string","description":"Natural-language company search request. Pass either prompt or plan.","minLength":1,"maxLength":20000},"route_id":{"type":"string","description":"Route id from the plan to execute.","minLength":1,"maxLength":200},"source":{"type":"string","enum":["company_search","hiring","google_maps"]},"source_filters":{"type":"object","description":"Same nested filters as the free preview; server validates every key.","additionalProperties":true},"source_intent":{"type":"string","description":"Optional intent override when planning from prompt."},"table":{"type":"string","description":"Existing table id or slug to receive rows. If omitted for live, Oxygen creates a table.","minLength":1,"maxLength":200},"table_name":{"type":"string","description":"Name the table this run creates. Ignored when `table` names an existing one."},"target_count":{"type":"number","description":"Desired company count when planning from prompt.","minimum":1,"maximum":50000},"tool_id":{"type":"string","description":"Tool id from the plan to execute.","minLength":1,"maxLength":200},"upsert_key":{"type":"string","description":"Column key used for live upsert. Must match the plan upsert key, usually domain.","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_companies_search_run"]}},"/api/cli/company-enrichment/preview":{"post":{"operationId":"postCompanyEnrichmentPreview","tags":["Company enrichment"],"summary":"Preview Company Enrichment","description":"Inspects an existing company/account table and plans a fill-missing company enrichment waterfall without provider calls or credit usage.\n\nMCP: `oxygen_company_enrichment_preview`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{},"fields":{},"force":{},"max_concurrency":{},"max_credits":{},"missingFields":{},"missing_fields":{"type":"array","description":"Company fields to fill.","items":{"type":"string","enum":["domain","linkedin_url","headcount","industry","funding","revenue","technologies","hiring_signals","company_profile"]},"minItems":1,"maxItems":9},"mode":{},"providers":{"type":"array","description":"Providers; scraper is the default for company profiles and domain resolution.","items":{"type":"string","enum":["scraper","blitzapi","apollo","peopledatalabs","theirstack","leadmagic","crustdata","ai_ark","prospeo"]},"minItems":1,"maxItems":9},"selection":{"type":"object","description":"Rows to inspect or run. Use mode all, limit, row_ids, or filter.","properties":{"mode":{"type":"string","enum":["all","limit","row_ids","filter"]},"limit":{"type":"integer","minimum":1,"maximum":500000},"row_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50000},"filters":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["mode"]},"slug":{},"table":{"type":"string","description":"Workspace table id or slug containing company/account rows.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_company_enrichment_preview"]}},"/api/cli/company-enrichment/run":{"post":{"operationId":"postCompanyEnrichmentRun","tags":["Company enrichment"],"summary":"Run Company Enrichment","description":"Queues a live fill-missing company enrichment waterfall over existing table rows. Live mode requires approved=true and max_credits after inspecting the preview; dry_run returns the plan without provider calls.\n\nMCP: `oxygen_company_enrichment_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required true for live mode after inspecting the preview and confirming the row scope and credit ceiling."},"fields":{},"force":{"type":"boolean","description":"Re-run the waterfall audit column even when it already has a value."},"max_concurrency":{"type":"integer","minimum":1,"maximum":1000,"description":"Maximum simultaneous rows; lower this to slow provider calls."},"max_credits":{"type":"number","description":"Required safety ceiling for live managed-key provider calls.","exclusiveMinimum":0},"missingFields":{},"missing_fields":{"type":"array","description":"Company fields to fill.","items":{"type":"string","enum":["domain","linkedin_url","headcount","industry","funding","revenue","technologies","hiring_signals","company_profile"]},"minItems":1,"maxItems":9},"mode":{"type":"string","description":"dry_run or live. Defaults to live.","enum":["dry_run","live"]},"providers":{"type":"array","description":"Providers; scraper is the default for company profiles and domain resolution.","items":{"type":"string","enum":["scraper","blitzapi","apollo","peopledatalabs","theirstack","leadmagic","crustdata","ai_ark","prospeo"]},"minItems":1,"maxItems":9},"selection":{"type":"object","description":"Rows to inspect or run. Use mode all, limit, row_ids, or filter.","properties":{"mode":{"type":"string","enum":["all","limit","row_ids","filter"]},"limit":{"type":"integer","minimum":1,"maximum":500000},"row_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50000},"filters":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["mode"]},"slug":{},"table":{"type":"string","description":"Workspace table id or slug containing company/account rows.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_company_enrichment_run"]}},"/api/cli/connectors":{"get":{"operationId":"getConnectors","tags":["Connectors"],"summary":"List Connected Apps","description":"Lists your OAuth apps, default workspaces, live event subscriptions and rolling 24-hour credit ceilings/usage; this_app marks the caller. Read-only, free. Change settings with oxygen_connector_update; inspect events with oxygen_connector_events_get.\n\nMCP: `oxygen_connector_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_connector_list"]}},"/api/cli/connectors/{connection}":{"get":{"operationId":"getConnectorsConnection","tags":["Connectors"],"summary":"Connected App Settings","description":"This app's OXYGEN settings (its default workspace) as a form: schema, values, layout. Read-only.\n\nMCP: `oxygen_connector_settings_read`, `oxygen_connector_settings_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"connection","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_connector_settings_read","oxygen_connector_settings_update"]},"patch":{"operationId":"connectors.update","tags":["Connectors"],"summary":"Change Connected App Settings","description":"Change one connected app's settings (ChatGPT, Claude, Codex or another app connected to OXYGEN with OAuth); only that app changes. --default-workspace: where it works without asking (the same setting the app changes when you pick a workspace inside it; latest wins; --clear-default-workspace makes it ask again). --credit-ceiling: the most credits it may spend in any 24 hours while it holds event subscriptions (--clear-credit-ceiling restores the plan default; above the default also needs --approve-above-default). Free; `connectors list` shows each app's current settings.\n\nMCP: `oxygen_connector_settings_update`, `oxygen_connector_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"connection","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"default_workspace":{"oneOf":[{"type":"string","minLength":1,"maxLength":200},{"type":"null"}],"description":"Workspace id, slug or exact name (you must be a member). null = ask each time."},"credit_ceiling":{"oneOf":[{"type":"integer","minimum":0,"maximum":25000},{"type":"null"}],"description":"Most credits the app may spend in any 24 hours while it holds event subscriptions. null = the plan default."},"approve_above_default":{"type":"boolean","description":"Approve a credit_ceiling above the plan default."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_connector_settings_update","oxygen_connector_update"]}},"/api/cli/connectors/{connection}/events":{"get":{"operationId":"getConnectorsConnectionEvents","tags":["Connectors"],"summary":"Connected App Event Subscriptions","description":"What one connected app (ChatGPT…) is subscribed to: the OXYGEN events it gets (reply classified, run settled, approval requested…), each with filters, status, workspace and expiry, plus what OXYGEN delivered to it and how each delivery went (status, attempts, failure category, times; never content). Read-only, free. Stop them with oxygen_connector_events_revoke.\n\nMCP: `oxygen_connector_events_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"connection","in":"path","required":true,"schema":{"type":"string"}},{"name":"deliveries","in":"query","required":false,"schema":{"type":"integer","description":"Recent deliveries per subscription (0-20, default 5).","minimum":0,"maximum":20}},{"name":"workspace","in":"query","required":false,"schema":{"type":"string","description":"Only this workspace (id, slug or name). Omit for all your workspaces.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_connector_events_get"]}},"/api/cli/connectors/{connection}/events/revoke":{"post":{"operationId":"connectors.events.revoke","tags":["Connectors"],"summary":"Revoke Connected App Event Subscriptions","description":"Stop OXYGEN sending events to one connected app: revoke one of its event subscriptions (--subscription <id>) or every live one (--subscription all), optionally only in one --workspace. Lasting: the app cannot renew a subscription revoked here, and nothing else about the app changes. Free; `connectors events get <app>` shows what it is subscribed to first.\n\nMCP: `oxygen_connector_events_revoke`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"connection","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subscription":{"type":"string","minLength":1,"maxLength":200,"description":"The subscription id from the app's event subscriptions, or \"all\" for every live one."},"workspace":{"type":"string","minLength":1,"maxLength":200,"description":"Only in this workspace (id, slug or exact name). Omit for all your workspaces."}},"required":["subscription"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_connector_events_revoke"]}},"/api/cli/context/assets":{"get":{"operationId":"getContextAssets","tags":["Context"],"summary":"List GTM Context Assets","description":"Lists durable workspace GTM assets such as playbooks, strategies, campaigns, positioning, personas, competitor notes, and research notes.\n\nMCP: `oxygen_context_assets_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"If true, includes archived assets when no status filter is set."}},{"name":"limit","in":"query","required":false,"schema":{"type":"number","description":"Defaults to 100.","minimum":1,"maximum":500}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","active","archived"]}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["playbook","strategy","campaign","positioning","brand","voice","persona","competitor","research_note","message_playbook","proposed_playbook_bullet","other"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_context_assets_list"]}},"/api/cli/context/assets/archive":{"post":{"operationId":"postContextAssetsArchive","tags":["Context"],"summary":"Archive GTM Context Asset","description":"Archives one durable workspace GTM context asset by id and writes a revision snapshot. Archiving the canonical brand/voice/positioning/playbook files a proposal and fails with knowledge_approval_required.\n\nMCP: `oxygen_context_asset_archive`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"assetId":{},"asset_id":{},"id":{"type":"string","description":"Context asset UUID.","minLength":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_context_asset_archive"]}},"/api/cli/context/assets/get":{"post":{"operationId":"postContextAssetsGet","tags":["Context"],"summary":"Get GTM Context Asset","description":"Reads one durable workspace GTM context asset by id.\n\nMCP: `oxygen_context_asset_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"assetId":{},"asset_id":{},"id":{"type":"string","description":"Context asset UUID.","minLength":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_context_asset_get"]}},"/api/cli/context/assets/search":{"post":{"operationId":"postContextAssetsSearch","tags":["Context"],"summary":"Search GTM Context Assets","description":"Relevance-ranked 'second brain' search across durable workspace GTM context assets (playbooks, strategies, positioning, personas, competitor + research notes). Full-text over each asset's title, summary, and body — the ranked superset of oxygen_context_assets_list. Supports websearch syntax (quoted phrases, OR, -exclude). Lexical, not semantic.\n\nMCP: `oxygen_context_asset_search`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"includeArchived":{},"include_archived":{"type":"boolean","description":"If true, includes archived assets when no status filter is set."},"limit":{"type":"number","description":"Defaults to 100.","minimum":1,"maximum":500},"q":{},"query":{"type":"string","description":"Search text. websearch syntax: \"quoted phrase\", term OR term, -exclude.","minLength":1},"status":{"type":"string","enum":["draft","active","archived"]},"tags":{"type":"array","description":"Tags that must be present.","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":20},"type":{"type":"string","enum":["playbook","strategy","campaign","positioning","brand","voice","persona","competitor","research_note","message_playbook","proposed_playbook_bullet","other"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_context_asset_search"]}},"/api/cli/context/assets/set-default":{"post":{"operationId":"postContextAssetsSetDefault","tags":["Context"],"summary":"Pin Canonical GTM Context Asset","description":"Pins a context asset as the canonical default for its type (or unpins with is_default=false). Of pinned assets, only an active brand, voice or positioning doc is auto-injected into AI message-column copy generation and readable as a context://<type> resource. Only one asset per type can be the canonical default. For brand/voice/positioning/playbook a pin or unpin files a proposal and fails with knowledge_approval_required; decide it with oxygen_knowledge_proposal_decide.\n\nMCP: `oxygen_context_asset_set_default`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"asset":{},"assetId":{},"asset_id":{},"id":{"type":"string","description":"Context asset UUID.","minLength":1},"isDefault":{},"is_default":{"type":"boolean","description":"Pin (true, the default) or unpin (false) as the canonical default for its type."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_context_asset_set_default"]}},"/api/cli/context/assets/upsert":{"post":{"operationId":"postContextAssetsUpsert","tags":["Context"],"summary":"Upsert GTM Context Asset","description":"Creates or updates a durable workspace GTM context asset (brand, voice, positioning, persona, playbook, ...). Omit id to create; include id to update. Canonical brand/voice/positioning/playbook are live copy: editing or archiving one files a proposal and fails with knowledge_approval_required, and is_default=true on those saves unpinned with pin.ok=false (decide via oxygen_knowledge_proposal_decide). Every write creates a revision snapshot.\n\nMCP: `oxygen_context_asset_upsert`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"asset":{"type":"object","description":"Context asset. Omit id to create; include id to update.","properties":{"id":{"type":"string","description":"Existing asset UUID when updating."},"type":{"type":"string","enum":["playbook","strategy","campaign","positioning","brand","voice","persona","competitor","research_note","message_playbook","proposed_playbook_bullet","other"]},"title":{"type":"string","minLength":1,"maxLength":240},"status":{"type":"string","enum":["draft","active","archived"]},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":50},"summary":{"type":"string","maxLength":2000},"body":{"type":"string","maxLength":200000},"data":{"type":"object","description":"Flexible structured asset data.","additionalProperties":true},"is_default":{"type":"boolean","description":"Ask to pin it as the canonical default for its type (only active brand/voice/positioning pins reach AI copy). brand/voice/positioning/playbook: saved unpinned, pin.ok=false with a proposal for oxygen_knowledge_proposal_decide; other types pin at once."}},"additionalProperties":false},"body":{},"data":{},"id":{},"is_default":{},"status":{},"summary":{},"tags":{},"title":{},"type":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_context_asset_upsert"]}},"/api/cli/context/canonical/get":{"post":{"operationId":"context.canonical.get","tags":["Context"],"summary":"Context canonical get","description":"Read the current canonical (pinned) voice, brand or positioning that AI copy uses, or any type's pinned asset. present=false means none is pinned; grounding_when_absent says what AI copy uses instead.\n\nCLI: `oxygen context canonical get`.\n\nMCP: `oxygen_context_canonical_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"Type to read: voice, brand or positioning (the canonical copy AI uses), or another context type such as playbook or persona."}},"required":["type"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_context_canonical_get"],"x-oxygen-cli-command":"oxygen context canonical get"}},"/api/cli/context/profile":{"get":{"operationId":"getContextProfile","tags":["Context"],"summary":"Get GTM Context Profile","description":"Reads durable workspace GTM memory: company, offering, ICP, market, GTM stack, and custom fields. Call this before planning lead sourcing, campaign strategy, ICP decisions, outbound copy, positioning, or prospect qualification.\n\nMCP: `oxygen_context_profile_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_context_profile_get"]}},"/api/cli/context/profile/update":{"post":{"operationId":"postContextProfileUpdate","tags":["Context"],"summary":"Update GTM Context Profile","description":"Updates durable workspace GTM memory. Provide only sections that changed; section objects shallow-merge with existing profile sections and every update creates a revision snapshot.\n\nMCP: `oxygen_context_profile_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"data":{},"patch":{},"profile":{"type":"object","description":"Company profile patch with any of company, offering, icp, market, gtm_stack, or custom.","properties":{"company":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"offering":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"icp":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"market":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"gtm_stack":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"custom":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true}},"additionalProperties":false},"summary":{"type":"string","description":"Concise current-state summary for humans and agents.","maxLength":4000},"user_correction":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_context_profile_update"]}},"/api/cli/context/resolve":{"post":{"operationId":"postContextResolve","tags":["Context"],"summary":"Resolve Workspace GTM Context","description":"Resolves workspace context and assets. purpose='onboarding' adds a research brief, inferred GTM hypotheses (user corrections win), workspace campaigns, data and access, and plays to offer; first tell the user what you are checking.\n\nMCP: `oxygen_context_resolve`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"assetStatus":{},"asset_status":{"type":"string","enum":["draft","active","archived","all"],"description":"Defaults to active."},"asset_types":{"type":"array","items":{"type":"string","enum":["playbook","strategy","campaign","positioning","brand","voice","persona","competitor","research_note","message_playbook","proposed_playbook_bullet","other"]},"maxItems":8},"includeArchived":{},"include_archived":{"type":"boolean","description":"If true, includes archived assets when asset_status is omitted."},"max_assets":{"type":"number","description":"Defaults to 10.","minimum":0,"maximum":50},"purpose":{"type":"string","enum":["general","onboarding","lead_sourcing","qualification","outbound_copy","workflow_design"],"description":"GTM task this context supports. Defaults to general."},"requireReady":{},"require_ready":{"type":"boolean","description":"If true, returns a conflict error when required context sections are missing."},"tags":{"type":"array","description":"Tags that all returned assets must contain.","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":20}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_context_resolve"]}},"/api/cli/context/synthesize":{"post":{"operationId":"postContextSynthesize","tags":["Context"],"summary":"Synthesize Voice or Campaign Learnings","description":"Runs one low-cost AI synthesis of workspace evidence into durable knowledge; every run spends a few managed AI credits, the preview included, and reports credits_used. kind='voice' learns your writing voice from your own SENT WhatsApp/LinkedIn messages and saves it; once its pin proposal is approved (oxygen_knowledge_proposal_decide) it is your canonical voice, which grounds message, reply, sequence and post drafts, Oxygent chats and message-writing AI columns. kind='campaign_learnings' distills auto-filed outreach outcomes (reply classifications, bounces, opt-outs, won/lost deals) plus sequence stats into a campaign-learnings wiki page; Oxygent chats, drafts and AI columns retrieve it where Knowledge retrieval is on. approved=false (default) previews; approved=true writes (learnings = a logged, revertible page revision; voice = saved + a pin proposal). approved=true without body synthesizes again (a second charge and new text): to keep what a preview showed, pass its body, or your edit, with approved=true, which makes no AI call. Fewer than 3 sent messages stops before the AI call with insufficient_source_messages and no charge.\n\nMCP: `oxygen_context_synthesize`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"false (default) previews without saving; true writes the result."},"body":{"type":"string","description":"With approved=true, save this edited markdown instead of re-synthesizing."},"kind":{"type":"string","enum":["voice","campaign_learnings"]},"limit":{"type":"number","description":"voice only: recent sent messages to learn from. Defaults to 200.","minimum":1,"maximum":200},"max_credits":{"type":"number","minimum":0,"description":"Hard cap OXYGEN enforces: the call is charged exactly its estimate, never more than this. A higher estimate is refused before any AI call, nothing charged, and the refusal reports the estimate (0 shows it free). Not needed with approved=true and body (no AI call)."},"sender":{},"sequence":{"type":"string","description":"campaign_learnings only: sequence id to scope onto that sequence's learnings page. Omit for the org-wide outreach-learnings page."},"sequence_id":{},"title":{"type":"string","description":"Title for a newly created asset/page."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_context_synthesize"]}},"/api/cli/copilot/sessions":{"get":{"operationId":"copilot.sessions.list","tags":["Copilot"],"summary":"Copilot list","description":"List attended Copilot sessions in this workspace.\n\nMCP: `oxygen_copilot_sessions_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Session status: active, completed, cancelled, failed. Separate from latest turn status; omit for all."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Newest sessions first. Default 50; native maximum 200 (larger values clamp)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_copilot_sessions_list"]},"post":{"operationId":"postCopilotSessions","tags":["Copilot"],"summary":"Start Copilot Session","description":"Starts an attended Workspace Copilot session on Oxygen Balanced by default. Starting is free; the next send starts inference using workspace credits. No inference budget is required. Legacy `budget_credits` and `per_turn_credit_ceiling` inputs remain accepted but neither authorizes nor caps spend. Paid provider calls, external writes and live runs keep their own approval and credit gates. Returns the session, its web deep-link and the next step.\n\nMCP: `oxygen_copilot_start`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"auto_approve":{"type":"boolean","description":"Start with auto-approve ON: every action runs without asking, paid and external ones included (sends, sequence starts, publishing). Each still records an approval decided automatically, bounded by its own credit cap and the workspace balance."},"auto_approve_policy":{},"budget_credits":{"type":"number","minimum":1,"description":"Legacy compatibility only: accepted and clamped, but does not authorize or cap attended Copilot inference."},"journey":{"type":"string","description":"Optional journey/use-case hint that biases the copilot's playbook (e.g. cold-outreach, crm-cleanup)."},"model":{"type":"string","description":"Optional priced model id override. Unknown ids fall back to the selected tier."},"per_turn_credit_ceiling":{"type":"number","minimum":1,"description":"Legacy compatibility only: accepted and clamped, but does not cap an attended turn."},"tier":{"type":"string","enum":["auto","low","medium","high"],"description":"Model tier: auto=Oxygen Auto, low=Oxygen Fast, medium=Oxygen Balanced (default), high=Oxygen Max."},"title":{"type":"string","description":"Optional human label for the session."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_copilot_start"]}},"/api/cli/copilot/sessions/{sessionId}":{"get":{"operationId":"getCopilotSessionsSessionId","tags":["Copilot"],"summary":"Get Copilot Session","description":"Reads one Workspace Copilot session: the session, its turns, the event timeline after `after_seq`, pending approvals, and the latest sequence cursor. Read-only. Pass `after_seq` to page only new events (pair it with oxygen_copilot_send's continuation hint to tail a running turn) and `event_limit` to bound the page.\n\nMCP: `oxygen_copilot_get`, `oxygen_copilot_send`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_copilot_get","oxygen_copilot_send"]},"patch":{"operationId":"copilot.sessions.update","tags":["Copilot"],"summary":"Copilot policy set","description":"Set an attended Copilot session's approval policy. `paid` (Auto-approve) is standing authorization for every action, paid and external ones included.\n\nCLI: `oxygen copilot policy set`.\n\nMCP: `oxygen_copilot_session_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"auto_approve_policy":{"type":"string","enum":["off","paid"]}},"required":["auto_approve_policy"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_copilot_session_update"],"x-oxygen-cli-command":"oxygen copilot policy set"}},"/api/cli/copilot/sessions/{sessionId}/approvals/{approvalId}":{"post":{"operationId":"postCopilotSessionsSessionIdApprovalsApprovalId","tags":["Copilot"],"summary":"Resolve Copilot Approval","description":"Resolve one pending Copilot approval. decision defaults to approve; reject abandons the step. Optional edits replace only email/reply content, bound to expected_args_hash. Recipients, scope and primitive approval/credit gates stay pinned. The turn continues after the decision.\n\nMCP: `oxygen_copilot_approve`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"approvalId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["approve","reject"],"description":"approve authorizes the previewed capability; reject abandons the step. Defaults to approve."},"edits":{"type":"object","additionalProperties":false,"properties":{"body":{"type":"string","minLength":1,"maxLength":100000},"html":{"type":"string","minLength":1,"maxLength":100000}},"description":"Reviewed email or reply content only. HTML emails require both body and html. Recipients and scope cannot change."},"expected_args_hash":{"type":"string","description":"Exact args_hash from the approval read; required with edits."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_copilot_approve"]}},"/api/cli/copilot/sessions/{sessionId}/attachments":{"get":{"operationId":"copilot.attachments.list","tags":["Copilot"],"summary":"Copilot attachments list","description":"List sent and unsent attachments in one Copilot session.\n\nCLI: `oxygen copilot attachments list`.\n\nMCP: `oxygen_copilot_attachments`, `oxygen_copilot_attachments_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_copilot_attachments","oxygen_copilot_attachments_list"],"x-oxygen-cli-command":"oxygen copilot attachments list"},"post":{"operationId":"copilot.attachments.prepare","tags":["Copilot"],"summary":"Copilot attachments prepare","description":"Reserve a Copilot attachment and return its scoped upload URL; complete only after uploading the exact bytes.\n\nCLI: `oxygen copilot attachments prepare`.\n\nMCP: `oxygen_copilot_attachment_prepare`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_name":{"type":"string"},"content_type":{"type":"string"},"content_length":{"type":"integer","minimum":1}},"required":["file_name","content_length"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_copilot_attachment_prepare"],"x-oxygen-cli-command":"oxygen copilot attachments prepare"}},"/api/cli/copilot/sessions/{sessionId}/attachments/{attachmentId}":{"get":{"operationId":"getCopilotSessionsSessionIdAttachmentsAttachmentId","tags":["Copilot"],"summary":"Read Chat File Original","description":"Reads bounded original chat-file bytes as base64 for current members; unsent files are private to their uploader. Resume with next_offset and version. Read-only, no credits.\n\nMCP: `oxygen_copilot_attachment_read`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"attachmentId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_copilot_attachment_read"]},"delete":{"operationId":"copilot.attachments.delete","tags":["Copilot"],"summary":"Copilot attachments delete","description":"Detach an unsent Copilot attachment; attachments already quoted by a turn cannot be removed.\n\nCLI: `oxygen copilot attachments delete`.\n\nMCP: `oxygen_copilot_attachment_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"attachmentId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_copilot_attachment_delete"],"x-oxygen-cli-command":"oxygen copilot attachments delete"}},"/api/cli/copilot/sessions/{sessionId}/attachments/{attachmentId}/complete":{"post":{"operationId":"copilot.attachments.complete","tags":["Copilot"],"summary":"Copilot attachments complete","description":"Verify and describe an uploaded Copilot attachment in its session.\n\nCLI: `oxygen copilot attachments complete`.\n\nMCP: `oxygen_copilot_attachment_complete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"attachmentId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_copilot_attachment_complete"],"x-oxygen-cli-command":"oxygen copilot attachments complete"}},"/api/cli/copilot/sessions/{sessionId}/cancel":{"post":{"operationId":"postCopilotSessionsSessionIdCancel","tags":["Copilot"],"summary":"Cancel Copilot Session","description":"Cancels an in-flight Workspace Copilot session: stops the current turn and marks the session cancelled so it makes no further inference calls. Cancelling an already-cancelled session is a no-op.\n\nMCP: `oxygen_copilot_cancel`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_copilot_cancel"]}},"/api/cli/copilot/sessions/{sessionId}/history":{"get":{"operationId":"copilot.history","tags":["Copilot"],"summary":"Copilot history","description":"Search past Oxygent chat messages and recorded app links, with source-turn URLs. Use chat.session_id from oxygents get/list. Results index recorded links, not Markdown-only links; their source turn may be a later update, not creation. Markdown remains searchable as message text.\n\nCLI: `oxygen copilot history`.\n\nMCP: `oxygen_copilot_history`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"query","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Literal substring in user and assistant messages; also filters recorded links. Omit to list recorded links only."}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Page offset, initially 0; continue with next_offset from the previous response."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"Items per page (default 30)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_copilot_history"],"x-oxygen-cli-command":"oxygen copilot history"}},"/api/cli/copilot/sessions/{sessionId}/turns":{"post":{"operationId":"postCopilotSessionsSessionIdTurns","tags":["Copilot"],"summary":"Send Copilot Message","description":"Sends one user message to a Workspace Copilot session and starts inference for that turn. Waits up to `wait_seconds` (capped at 55s) while polling the session, advancing an event cursor, then returns the turn's partial state: the assistant text accumulated so far plus any tool calls and pending approvals. If the turn is still running at the deadline it returns `terminal: false` with a `continue_with` hint telling you to call oxygen_copilot_get at the given after_seq cursor to keep tailing. A turn that needs a paid or external capability pauses as awaiting_input with a pending approval — resolve it with oxygen_copilot_approve. Managed inference uses workspace credits.\n\nMCP: `oxygen_copilot_send`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"attachment_ids":{"type":"array","items":{"type":"string","minLength":1},"description":"Ids of files already attached to this session (see oxygen_copilot_attachments) to send with this message. Uploading a new file needs local disk access, so it lives in `oxygen copilot attach` and the web composer, not here."},"context":{"type":"object","additionalProperties":true,"description":"Optional structured context object forwarded to the turn (e.g. selected table id, row ids)."},"interrupt":{"type":"boolean","description":"Copilot chats: stop a still-working turn and run this message next instead of being refused. Not with attachment_ids."},"message":{"type":"string","minLength":1,"description":"The user message for this turn."},"surface_context":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_copilot_send"]}},"/api/cli/copilot/sessions/{sessionId}/turns/{turnId}/feedback":{"post":{"operationId":"copilot.feedback","tags":["Copilot"],"summary":"Copilot feedback","description":"Rate one attended Copilot turn and optionally explain the rating.\n\nCLI: `oxygen copilot feedback`.\n\nMCP: `oxygen_copilot_feedback`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"turnId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rating":{"type":"string","enum":["up","down"]},"comment":{"type":"string"}},"required":["rating"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_copilot_feedback"],"x-oxygen-cli-command":"oxygen copilot feedback"}},"/api/cli/copilot/sessions/{sessionId}/turns/{turnId}/interrupt":{"post":{"operationId":"copilot.interrupt","tags":["Copilot"],"summary":"Copilot interrupt","description":"Request cancellation of one Copilot turn. Read the session again to confirm it stopped.\n\nMCP: `oxygen_copilot_interrupt`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"turnId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_copilot_interrupt"]}},"/api/cli/crm/activities":{"post":{"operationId":"postCrmActivities","tags":["CRM"],"summary":"Log CRM Activity","description":"Logs a timeline activity (note, call, meeting, email, stage change, or a signal such as website_visit) on a CRM record; an inbound signal type also lands in the Signals feed. row_id takes the record's rowId or an identity such as an email; create a missing person first with oxygen_crm_record_assert. Defaults to dry_run; pass mode='live' or live=true only after inspecting the preview. Idempotent on (source_provider, provider_event_id).\n\nMCP: `oxygen_crm_activity_log`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"activity_type":{"type":"string","description":"Activity type, such as note, call, meeting_booked, email_reply, stage_changed, or a signal: website_visit, profile_view, post_reaction, new_follower.","minLength":1,"maxLength":60},"body":{"type":"string","description":"Longer activity body or details.","maxLength":20000},"channel":{"type":"string","description":"Channel, such as email, linkedin, or phone.","maxLength":60},"direction":{"type":"string","description":"Activity direction.","enum":["inbound","outbound","internal","system"]},"links":{},"live":{"type":"boolean","description":"Same as mode='live'."},"metadata":{"type":"object","description":"Extra activity metadata.","additionalProperties":true},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"occurred_at":{"type":"string","description":"ISO-8601 timestamp the activity occurred. Defaults to now.","maxLength":60},"provider_event_id":{"type":"string","description":"Provider event id (dedupes redelivered events).","maxLength":200},"source_provider":{"type":"string","description":"Provider that produced the activity (for idempotency).","maxLength":120},"summary":{"type":"string","description":"Short one-line summary of the activity.","maxLength":1000}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_activity_log"]}},"/api/cli/crm/assert":{"post":{"operationId":"postCrmAssert","tags":["CRM"],"summary":"Assert CRM Record","description":"Creates or updates one CRM record by object identity. Defaults to dry_run; pass mode='live' or live=true only after inspecting the preview. The dry run's auto_run says whether the live write queues standing enrichment (off: no credits).\n\nMCP: `oxygen_crm_record_assert`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"identity":{},"identityKey":{},"identityValue":{},"identity_key":{"type":"string","description":"CRM identity key on the object, such as domain for companies or email for people.","minLength":1,"maxLength":120},"identity_value":{"type":"string","description":"Identity value to assert, such as acme.com or ceo@acme.com.","minLength":1,"maxLength":500},"key":{},"live":{"type":"boolean","description":"Same as mode='live'."},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"object":{"type":"string","description":"CRM object slug, e.g. people.","minLength":1,"maxLength":120},"objectSlug":{},"object_slug":{},"value":{},"values":{"type":"object","description":"CRM attribute values keyed by column key. The identity column is filled automatically when omitted.","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_record_assert"]}},"/api/cli/crm/automation":{"get":{"operationId":"getCrmAutomation","tags":["CRM"],"summary":"CRM Automation Rules","description":"Lists the standing CRM automation templates and whether each is armed. An armed rule is the scoped standing permission that lets bridged provider signals (replies, meetings, signups) advance a lead's CRM stage automatically — a FREE internal write, no per-event approval. Read-only.\n\nMCP: `oxygen_crm_automation_rules_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_automation_rules_list"]},"post":{"operationId":"postCrmAutomation","tags":["CRM"],"summary":"Arm CRM Automation Rule","description":"Arms or disarms a standing CRM automation template (e.g. crm-lead-stage-router). Defaults to dry_run. After inspecting that preview, live arming requires approved=true plus a positive max_credits ceiling per event delivery; this binds standing tool authority to the exact workflow revision even when today's CRM writes consume zero credits.\n\nMCP: `oxygen_crm_automation_rule_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Confirm standing tool authority for this exact live workflow revision after inspecting the dry-run preview."},"armed":{"type":"boolean","description":"true to arm the template, false to disarm it."},"config":{"type":"object","description":"Optional per-template config.","additionalProperties":true},"live":{"type":"boolean","description":"Same as mode='live'."},"max_credits":{"type":"number","exclusiveMinimum":0,"description":"Hard credit ceiling for each event delivery. Required when arming live."},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"template_id":{"type":"string","description":"Template id, such as crm-lead-stage-router, crm-meeting-booked, or crm-signup-to-person.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_automation_rule_set"]}},"/api/cli/crm/automation/audit":{"get":{"operationId":"getCrmAutomationAudit","tags":["CRM"],"summary":"CRM Automation Audit","description":"Shows recent CRM automation rule changes (who armed/disarmed which template), newest first. Read-only.\n\nMCP: `oxygen_crm_automation_audit`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum audit entries to return. Defaults to 25.","minimum":1,"maximum":100}},{"name":"template_id","in":"query","required":false,"schema":{"type":"string","description":"Filter to one template id.","maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_automation_audit"]}},"/api/cli/crm/enrichment":{"get":{"operationId":"getCrmEnrichment","tags":["CRM"],"summary":"CRM Automatic Enrichment","description":"Read CRM automatic-enrichment configuration for companies/people: list is free via the call gateway; omit object and set backfill=false to skip backlog counts. Object reads retain counts. projection=summary bounds reads; value/path retrieves complete native JSON with next_cursor. set/enable/disable arm standing unattended Table auto-run within max_credits per batch. backfill previews existing records for free; paid live batches require approval and max_credits.\n\nMCP: `oxygen_crm_enrichment`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"backfill","in":"query","required":false,"schema":{"type":"boolean","description":"list without object: include stored historical backlog counts (default true). false skips the scans; object reads ignore it. Never runs enrichment."}},{"name":"object","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"CRM object: companies or people."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_enrichment"]},"post":{"operationId":"postCrmEnrichment","tags":["CRM"],"summary":"CRM Automatic Enrichment","description":"Read CRM automatic-enrichment configuration for companies/people: list is free via the call gateway; omit object and set backfill=false to skip backlog counts. Object reads retain counts. projection=summary bounds reads; value/path retrieves complete native JSON with next_cursor. set/enable/disable arm standing unattended Table auto-run within max_credits per batch. backfill previews existing records for free; paid live batches require approval and max_credits.\n\nMCP: `oxygen_crm_enrichment`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"disable":{},"enable":{},"force":{"type":"boolean","description":"set: re-enrich records that already have values."},"max_credits":{"type":"number","description":"set: credit ceiling per auto-run batch. backfill: ceiling for this batch (required when live).","minimum":0},"object":{"type":"string","minLength":1,"maxLength":120,"description":"CRM object: companies or people."},"presets":{"type":"array","description":"set: the whole enabled set, replacing what is armed. [] arms nothing.","items":{"type":"string"},"maxItems":20},"set":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_enrichment"]}},"/api/cli/crm/enrichment/backfill":{"post":{"operationId":"postCrmEnrichmentBackfill","tags":["CRM"],"summary":"CRM Automatic Enrichment","description":"Read CRM automatic-enrichment configuration for companies/people: list is free via the call gateway; omit object and set backfill=false to skip backlog counts. Object reads retain counts. projection=summary bounds reads; value/path retrieves complete native JSON with next_cursor. set/enable/disable arm standing unattended Table auto-run within max_credits per batch. backfill previews existing records for free; paid live batches require approval and max_credits.\n\nMCP: `oxygen_crm_enrichment`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"all":{"type":"boolean","description":"backfill: every pending record, up to 5000."},"approved":{"type":"boolean","description":"backfill: approve this batch after reading the preview."},"limit":{"type":"integer","description":"backfill: records in this batch. Default 50.","minimum":1,"maximum":5000},"live":{"type":"boolean","description":"backfill: run it. Default is a free preview."},"max_credits":{"type":"number","description":"set: credit ceiling per auto-run batch. backfill: ceiling for this batch (required when live).","minimum":0},"object":{"type":"string","minLength":1,"maxLength":120,"description":"CRM object: companies or people."},"presets":{"type":"array","description":"set: the whole enabled set, replacing what is armed. [] arms nothing.","items":{"type":"string"},"maxItems":20}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_enrichment"]}},"/api/cli/crm/fields":{"post":{"operationId":"postCrmFields","tags":["CRM"],"summary":"Fill CRM Fields","description":"Fills empty CRM fields from stored enrichment payloads. Free: no provider call, credits, external read, or overwrite. Dry-run by default; use live after reviewing the preview.\n\nMCP: `oxygen_crm_fields`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Rows per object (default 2000; max 20000).","minimum":1,"maximum":20000},"live":{"type":"boolean","description":"Sets live mode; default is dry-run."},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"object":{"type":"string","description":"CRM object slug, e.g. people.","minLength":1,"maxLength":120},"objects":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_fields"]}},"/api/cli/crm/files/{attachmentId}":{"delete":{"operationId":"crm.files.delete","tags":["CRM"],"summary":"CRM files detach","description":"Detach a CRM attachment by attachment_id, preserving the stored file.\n\nMCP: `oxygen_crm_file_delete`, `oxygen_crm_files_detach`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"attachmentId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_crm_file_delete","oxygen_crm_files_detach"]}},"/api/cli/crm/files/{attachmentId}/download":{"get":{"operationId":"crm.files.download","tags":["CRM"],"summary":"CRM files download","description":"Download a tenant-owned record attachment by attachment_id. The native authenticated response contains its exact bytes.\n\nCLI: `oxygen crm files download`.\n\nMCP: `oxygen_crm_file_download`, `oxygen_crm_files_read`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"attachmentId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_file_download","oxygen_crm_files_read"],"x-oxygen-cli-command":"oxygen crm files download"}},"/api/cli/crm/merge":{"post":{"operationId":"postCrmMerge","tags":["CRM"],"summary":"Merge CRM Records","description":"Merges two CRM records of the same object into one. The survivor's fields win; the loser's values only fill columns the survivor left empty (survivor-wins-with-loser-fill), and the loser's identities, relationships, list memberships, and timeline are relinked onto the survivor before the loser is tombstoned in one transaction. Defaults to mode='dry_run', which returns the field-level survivor/loser diff and the relink plan: THIS DIFF IS THE APPROVAL SURFACE. A live merge requires BOTH mode='live' (or live=true) AND confirm=true. Merge is a free internal write (no credits).\n\nMCP: `oxygen_crm_merge`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Required true for a live merge, confirming you inspected the dry-run field diff."},"fieldOverrides":{},"field_overrides":{"type":"object","description":"Resolved field values keyed by column key, overriding survivor-wins-with-loser-fill for those columns.","additionalProperties":true},"live":{"type":"boolean","description":"Same as mode='live'."},"loser_row_id":{"type":"string","description":"Row id of the record to MERGE AWAY and tombstone.","minLength":1,"maxLength":120},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"object":{"type":"string","description":"CRM object slug, e.g. people.","minLength":1,"maxLength":120},"objectSlug":{},"object_slug":{},"survivor_row_id":{"type":"string","description":"Row id of the record to KEEP.","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_crm_merge"]}},"/api/cli/crm/notes/{noteId}":{"patch":{"operationId":"crm.notes.update","tags":["CRM"],"summary":"CRM notes update","description":"Edit a CRM note's body, title or pinned state; an empty title clears it.\n\nMCP: `oxygen_crm_note_update`, `oxygen_crm_notes_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"noteId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"Replacement Markdown; trimmed text maximum 20000 characters. Empty or whitespace text is ignored."},"title":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"Replacement title; trimmed maximum 300 characters. Null or empty clears."},"pinned":{"type":"boolean","description":"Whether the note is pinned; false unpins."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_note_update","oxygen_crm_notes_update"]},"delete":{"operationId":"crm.notes.delete","tags":["CRM"],"summary":"CRM notes delete","description":"Delete one CRM note in this workspace.\n\nMCP: `oxygen_crm_note_delete`, `oxygen_crm_notes_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"noteId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_crm_note_delete","oxygen_crm_notes_delete"]}},"/api/cli/crm/objects":{"get":{"operationId":"getCrmObjects","tags":["CRM"],"summary":"List CRM Objects","description":"Lists CRM object names and table bindings in compact cursor pages. Describe one object for field configuration. Defaults to a bounded compact result; full projection is explicit.\n\nMCP: `oxygen_crm_objects_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_objects_list"]},"post":{"operationId":"postCrmObjects","tags":["CRM"],"summary":"Create CRM Custom Object","description":"Creates or repairs a custom CRM object (its own object-backed table, attributes, and identities) over the same engine the standard objects use. Reserved slugs (companies, people, deals, lists, activities) are rejected. Define relationships AFTER create with oxygen_crm_relationship_define.\n\nMCP: `oxygen_crm_object_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"columns":{"type":"array","description":"Column definitions, each { key, label, dataType (text|numeric|boolean|jsonb|timestamptz), semanticType, isRecordLabel?, options? }. One column must be the record label.","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"data_type":{"type":"string","enum":["text","numeric","boolean","jsonb","timestamptz"]},"dataType":{"type":"string","enum":["text","numeric","boolean","jsonb","timestamptz"]},"semantic_type":{"type":"string","minLength":1,"description":"Required with data_type; text for a generic field, or a semantic such as company.name, company.domain or email."},"semanticType":{"type":"string","minLength":1,"description":"Alias of semantic_type."},"kind":{"type":"string"},"attribute_kind":{"type":"string"},"attributeKind":{"type":"string"},"option_model_type":{"type":"string"},"optionModelType":{"type":"string"},"is_required":{"type":"boolean"},"isRequired":{"type":"boolean"},"is_unique":{"type":"boolean"},"isUnique":{"type":"boolean"},"is_multivalue":{"type":"boolean"},"isMultivalue":{"type":"boolean"},"is_record_label":{"type":"boolean"},"isRecordLabel":{"type":"boolean"},"is_record_image":{"type":"boolean"},"isRecordImage":{"type":"boolean"},"kanban_candidate":{"type":"boolean"},"kanbanCandidate":{"type":"boolean"},"display_order":{"type":"number"},"displayOrder":{"type":"number"},"options":{"type":"array","items":{"type":"object","additionalProperties":true}},"definition":{"type":"object","additionalProperties":true},"attribute_metadata":{"type":"object","additionalProperties":true},"attributeMetadata":{"type":"object","additionalProperties":true}},"required":["key","label"],"allOf":[{"anyOf":[{"required":["data_type"]},{"required":["dataType"]}]},{"anyOf":[{"required":["semantic_type"]},{"required":["semanticType"]}]}],"additionalProperties":false},"maxItems":60},"displayName":{},"display_name":{"type":"string","description":"Human-readable object name, such as Projects.","minLength":1,"maxLength":200},"identities":{"type":"array","description":"Identity definitions, each { columnKey, normalization (email_v1|domain_v1|linkedin_url_v1|exact_text_v1|uuid_v1), isPrimary? }. At most one primary.","items":{"type":"object","properties":{"column_key":{"type":"string"},"columnKey":{"type":"string"},"normalization":{"type":"string","enum":["email_v1","domain_v1","linkedin_url_v1","exact_text_v1","uuid_v1"]},"slug":{"type":"string"},"display_name":{"type":"string"},"displayName":{"type":"string"},"identity_type":{"type":"string"},"identityType":{"type":"string"},"is_primary":{"type":"boolean"},"isPrimary":{"type":"boolean"},"is_required_for_assert":{"type":"boolean"},"isRequiredForAssert":{"type":"boolean"},"priority":{"type":"number"}},"required":["normalization"],"additionalProperties":false},"maxItems":20},"labelColumnKey":{},"label_column":{"type":"string","description":"Column key to use as the record label. Defaults to the isRecordLabel column or the first column.","minLength":1,"maxLength":120},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"pluralName":{},"plural_name":{"type":"string","description":"Plural display name, such as Projects.","minLength":1,"maxLength":200},"project":{"type":"string","description":"Project id or slug for the created CRM table.","minLength":1,"maxLength":200},"relationships":{},"singularName":{},"singular_name":{"type":"string","description":"Singular display name, such as Project.","minLength":1,"maxLength":200},"slug":{"type":"string","description":"Object slug (snake_case), such as projects or vendors. Slugs CRM already uses for its own objects and pages (companies, deals, tasks, dashboards, ...) are rejected.","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_object_create"]}},"/api/cli/crm/objects/{object}":{"get":{"operationId":"getCrmObjectsObject","tags":["CRM"],"summary":"Describe CRM Object","description":"Describes one configured CRM object, including its table binding, attributes, identities, and relationships. Pass attribute=<key> to read just that one field instead of the whole object. Custom slugs accept hyphens. A deleted custom object answers crm_object_not_found with state archived; its next_step, the delete dry_run, reports the purge time.\n\nMCP: `oxygen_crm_object_describe`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"attribute","in":"query","required":false,"schema":{"type":"string","description":"Narrow the answer to one field by its key, e.g. pipeline_stage.","minLength":1,"maxLength":120}},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["audiences"],"description":"audiences: Tables bound to an Audience object, with counts."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_object_describe"]},"delete":{"operationId":"deleteCrmObjectsObject","tags":["CRM"],"summary":"Delete CRM Custom Object","description":"Deletes one CUSTOM CRM object and schedules its backing table for 14-day recoverable deletion. Standard objects (companies, people, deals) are permanent. Defaults to dry_run, returning row, attribute, identity, relationship, and edge counts without writes. Live requires mode='live' (or live=true) AND confirm=true after inspecting that preview. keep_table=true preserves the rows as an ordinary workspace table. Re-run on an already-deleted object, it reports alreadyArchived=true with its table's deletion state and purge time. Restoring that table returns its rows as an ordinary table; the object stays deleted. Purging it also removes the object's archived definition.\n\nMCP: `oxygen_crm_object_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"confirm","in":"query","required":false,"schema":{"type":"boolean","description":"Required true for a live delete, confirming you inspected the dry-run impact."}},{"name":"keepTable","in":"query","required":false,"schema":{}},{"name":"keep_table","in":"query","required":false,"schema":{"type":"boolean","description":"Keep the backing table as an ordinary workspace table instead of scheduling it for deletion. Rows are preserved either way until the purge runs. Ignored once the table is already scheduled."}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]}},{"name":"purgeAfterDays","in":"query","required":false,"schema":{}},{"name":"purge_after_days","in":"query","required":false,"schema":{"type":"number","description":"Days until the backing table's physical purge. Defaults to 14; restorable until then. Ignored when keep_table is true or the table is already scheduled.","minimum":0,"maximum":365}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_crm_object_delete"]}},"/api/cli/crm/objects/{object}/attributes":{"post":{"operationId":"postCrmObjectsObjectAttributes","tags":["CRM"],"summary":"Add CRM Object Attribute","description":"Adds one attribute (column) to an existing CRM object, optionally promoting it to an identity. Works on custom objects and on companies/people/deals — a field you add is yours and survives oxygen_crm_setup.\n\nMCP: `oxygen_crm_object_add_attribute`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"data_type":{"type":"string","enum":["text","numeric","boolean","jsonb","timestamptz"]},"dataType":{"type":"string","enum":["text","numeric","boolean","jsonb","timestamptz"]},"semantic_type":{"type":"string","minLength":1,"description":"Required with data_type; text for a generic field, or a semantic such as company.name, company.domain or email."},"semanticType":{"type":"string","minLength":1,"description":"Alias of semantic_type."},"kind":{"type":"string"},"attribute_kind":{"type":"string"},"attributeKind":{"type":"string"},"option_model_type":{"type":"string"},"optionModelType":{"type":"string"},"is_required":{"type":"boolean"},"isRequired":{"type":"boolean"},"is_unique":{"type":"boolean"},"isUnique":{"type":"boolean"},"is_multivalue":{"type":"boolean"},"isMultivalue":{"type":"boolean"},"is_record_label":{"type":"boolean"},"isRecordLabel":{"type":"boolean"},"is_record_image":{"type":"boolean"},"isRecordImage":{"type":"boolean"},"kanban_candidate":{"type":"boolean"},"kanbanCandidate":{"type":"boolean"},"display_order":{"type":"number"},"displayOrder":{"type":"number"},"options":{"type":"array","items":{"type":"object","additionalProperties":true}},"definition":{"type":"object","additionalProperties":true},"attribute_metadata":{"type":"object","additionalProperties":true},"attributeMetadata":{"type":"object","additionalProperties":true}},"required":["key","label"],"allOf":[{"anyOf":[{"required":["data_type"]},{"required":["dataType"]}]},{"anyOf":[{"required":["semantic_type"]},{"required":["semanticType"]}]}],"additionalProperties":false,"description":"Column definition { key, label, dataType (text|numeric|boolean|jsonb|timestamptz), semanticType, options? }."},"identity":{},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_object_add_attribute"]}},"/api/cli/crm/objects/{object}/attributes/{attribute}":{"patch":{"operationId":"patchCrmObjectsObjectAttributesAttribute","tags":["CRM"],"summary":"Update CRM Object Attribute","description":"Changes one field on a CRM object: rename it, make it required or optional, or replace the choices of a select/status field. The field's key never changes, so prompts and formulas that read it keep working. An Oxygen-shipped field on companies/people/deals can be renamed and its choices changed (its key, type and required flag stay); a field the workspace added is fully editable. Defaults to dry_run.\n\nMCP: `oxygen_crm_object_update_attribute`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"attribute","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"display_name":{"type":"string","description":"New display name for the field.","minLength":1,"maxLength":200},"is_required":{"type":"boolean","description":"Make the field required (true) or optional (false)."},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"options":{"type":"array","description":"Replacement choice list for a select/status field: [{ value, label, color? }]. Keep an existing value to keep the records that hold it.","items":{"type":"object","additionalProperties":true}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_object_update_attribute"]},"delete":{"operationId":"deleteCrmObjectsObjectAttributesAttribute","tags":["CRM"],"summary":"Remove CRM Object Attribute","description":"Removes a field the workspace added to a CRM object. The column is archived (restorable via `columns restore <table> <key>`, which brings the field back; no cell destroyed), the object stops listing it, and the key is free for a new field at once. Oxygen-shipped fields, the title field, identity fields and relations are refused. Defaults to dry_run.\n\nMCP: `oxygen_crm_object_remove_attribute`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"attribute","in":"path","required":true,"schema":{"type":"string"}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_crm_object_remove_attribute"]}},"/api/cli/crm/objects/{object}/duplicates":{"get":{"operationId":"getCrmObjectsObjectDuplicates","tags":["CRM"],"summary":"CRM Duplicate Candidates","description":"Lists ranked duplicate-candidate record PAIRS for one CRM object via two signals: identity-overlap (the same normalized identity value attached to more than one record) and fuzzy-label (records whose labels match), across every record. Each pair names a default survivor (older record) and loser; pass them to oxygen_crm_merge. Pages: pass nextCursor back as cursor until it is null. Read-only — no writes.\n\nMCP: `oxygen_crm_duplicates`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"The previous page's nextCursor.","minLength":1,"maxLength":2000}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum candidate pairs per page. Defaults to 25, max 100.","minimum":1,"maximum":100}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_duplicates"]}},"/api/cli/crm/objects/{object}/records/{rowId}":{"get":{"operationId":"getCrmObjectsObjectRecordsRowId","tags":["CRM"],"summary":"Get CRM Record","description":"Gets one record with identities and relationships. Default compact bounds the receipt and names omitted cells; recover them with oxygen_table_row_inspect projection=value. full includes object configuration.\n\nMCP: `oxygen_crm_record_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_record_get"]}},"/api/cli/crm/objects/{object}/records/{rowId}/brief":{"get":{"operationId":"getCrmObjectsObjectRecordsRowIdBrief","tags":["CRM"],"summary":"GET /api/cli/crm/objects/{object}/records/{rowId}/brief","description":"Fields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}},{"name":"max_chars","in":"query","required":false,"schema":{}},{"name":"sections","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false}},"/api/cli/crm/objects/{object}/records/{rowId}/connections":{"get":{"operationId":"crm.connections","tags":["CRM"],"summary":"CRM connections","description":"Read a CRM record's connected conversations, sequence enrollments and related activity.\n\nMCP: `oxygen_crm_connections`, `oxygen_crm_record_connections`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}},{"name":"projection","in":"query","required":false,"schema":{"type":"string","enum":["compact","full"],"description":"Compact returns identifiers and short communication previews. HTTP default full."}},{"name":"max_chars","in":"query","required":false,"schema":{"type":"integer","minimum":2000,"maximum":40000,"description":"Complete recent-window response; hasMore includes omitted links."}},{"name":"conversation_limit","in":"query","required":false,"schema":{"type":"integer","minimum":1}},{"name":"sequence_limit","in":"query","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_connections","oxygen_crm_record_connections"]}},"/api/cli/crm/objects/{object}/records/{rowId}/files":{"get":{"operationId":"getCrmObjectsObjectRecordsRowIdFiles","tags":["CRM"],"summary":"CRM Record Files","description":"Lists attached originals, newest first: files[].id is the attachment id; fileId is storage identity, name is filename, sizeBytes is byte length and mimeType is opaque. Read original bytes with oxygen_crm_files_read.\n\nMCP: `oxygen_crm_files_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_files_list"]},"post":{"operationId":"crm.files.attach_inline","tags":["CRM"],"summary":"CRM files attach inline","description":"Attach inline base64 bytes to a CRM record; each call creates a new file and attachment, including identical retries. If a response is lost, inspect the record's files before deciding to retry. Entire request must fit 2 MB; larger originals use upload prepare/complete. No credits.\n\nCLI: `oxygen crm files attach-inline`.\n\nMCP: `oxygen_crm_file_attach`, `oxygen_crm_files_attach`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Original filename."},"content_base64":{"type":"string","minLength":1,"description":"Inline bytes; entire JSON request must fit 2 MB. Larger files use upload prepare/complete."},"label":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"Optional record-local label; trimmed maximum 300 characters."}},"required":["name","content_base64"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_file_attach","oxygen_crm_files_attach"],"x-oxygen-cli-command":"oxygen crm files attach-inline"}},"/api/cli/crm/objects/{object}/records/{rowId}/files/{fileId}/uploaded":{"post":{"operationId":"crm.files.complete","tags":["CRM"],"summary":"CRM files complete upload","description":"Verify a reserved CRM upload and attach it to its record; mismatched bytes remain pending.\n\nCLI: `oxygen crm files complete-upload`.\n\nMCP: `oxygen_crm_file_complete_upload`, `oxygen_crm_files_upload_complete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}},{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"Record-local attachment label. Omitted, null or empty preserves an existing label and leaves a new attachment unlabeled. Filename is unchanged. Trimmed maximum 300 characters."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_file_complete_upload","oxygen_crm_files_upload_complete"],"x-oxygen-cli-command":"oxygen crm files complete-upload"}},"/api/cli/crm/objects/{object}/records/{rowId}/files/upload-url":{"post":{"operationId":"crm.files.prepare","tags":["CRM"],"summary":"CRM files prepare upload","description":"Reserve a CRM file upload by exact name, length and SHA-256; returns a scoped upload URL.\n\nCLI: `oxygen crm files prepare-upload`.\n\nMCP: `oxygen_crm_file_prepare_upload`, `oxygen_crm_files_upload_prepare`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","pattern":"\\S","description":"Original filename; must remain nonempty after trimming."},"byte_length":{"type":"integer","minimum":0,"maximum":104857600,"description":"Exact byte length; maximum 100 MiB."},"sha256":{"type":"string","pattern":"^\\s*[A-Fa-f0-9]{64}\\s*$","description":"Hex SHA-256 of the exact bytes to PUT; case and surrounding whitespace are normalized."}},"required":["name","byte_length","sha256"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_file_prepare_upload","oxygen_crm_files_upload_prepare"],"x-oxygen-cli-command":"oxygen crm files prepare-upload"}},"/api/cli/crm/objects/{object}/records/{rowId}/keep":{"post":{"operationId":"postCrmObjectsObjectRecordsRowIdKeep","tags":["CRM"],"summary":"Keep Sample Record","description":"Keeps one sample record as real. New workspaces start with sample companies, CEOs and deals: reads mark them _sample: true (sample: true on oxygen_crm_pipeline deals) and totals leave them out. Call only when the user says the record is real; free, no undo. Linked records stay as they are: a kept deal's company and contact stay samples until each is kept.\n\nMCP: `oxygen_crm_record_keep`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_record_keep"]}},"/api/cli/crm/objects/{object}/records/{rowId}/notes":{"get":{"operationId":"getCrmObjectsObjectRecordsRowIdNotes","tags":["CRM"],"summary":"CRM Record Notes","description":"Lists a CRM record's notes, pinned first then newest, with cursor pagination.\n\nMCP: `oxygen_crm_notes_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Pagination cursor from a previous page.","minLength":1,"maxLength":500}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum notes to return. Defaults to 25.","minimum":1,"maximum":100}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_notes_list"]},"post":{"operationId":"postCrmObjectsObjectRecordsRowIdNotes","tags":["CRM"],"summary":"Write CRM Note","description":"Writes a note on a CRM record; a website visit, profile view or reaction the person made is a Signal: log it with oxygen_crm_activity_log. Free, internal and editable afterwards, so it writes immediately rather than previewing first. Also lands on the record's timeline.\n\nMCP: `oxygen_crm_notes_add`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"Note text. Markdown.","minLength":1,"maxLength":20000},"pinned":{"type":"boolean","description":"Pin the note to the top of the record's notes."},"title":{"type":"string","description":"Optional note title.","maxLength":300}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_notes_add"]}},"/api/cli/crm/objects/{object}/records/{rowId}/related":{"get":{"operationId":"getCrmObjectsObjectRecordsRowIdRelated","tags":["CRM"],"summary":"CRM Related Records","description":"Lists the records linked to one CRM record, grouped by relationship. Each group carries its real total, not just the preview length.\n\nMCP: `oxygen_crm_record_related`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}},{"name":"preview_limit","in":"query","required":false,"schema":{"type":"integer","description":"Records to preview per group. Defaults to 6.","minimum":1,"maximum":50}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_record_related"]}},"/api/cli/crm/objects/{object}/records/{rowId}/tags":{"post":{"operationId":"postCrmObjectsObjectRecordsRowIdTags","tags":["CRM"],"summary":"Tag CRM Record","description":"Adds/removes workspace tags on one CRM record (Tags primitive; see oxygen_tags_list). Delta semantics: add unions, remove subtracts, remove wins. Standard objects carry the tags attribute after oxygen_crm_setup.\n\nMCP: `oxygen_crm_tag`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"add":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"Workspace tags to add."},"remove":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"Workspace tags to remove."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_tag"]}},"/api/cli/crm/objects/{object}/records/{rowId}/tasks":{"get":{"operationId":"getCrmObjectsObjectRecordsRowIdTasks","tags":["CRM"],"summary":"CRM Record Tasks","description":"Lists record to-dos, or workspace tasks when object and row_id are both omitted. Workspace defaults to open; assignee=me reads your work. Distinct from the Voice dial queue.\n\nMCP: `oxygen_crm_tasks_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":500,"description":"Previous nextCursor."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Maximum tasks; default 50."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","completed","cancelled","all"],"description":"Workspace default open; record default all. all omits the API filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_tasks_list"]},"post":{"operationId":"postCrmObjectsObjectRecordsRowIdTasks","tags":["CRM"],"summary":"Create CRM Task","description":"Creates a task on a CRM record — the human to-do, not the phone queue oxygen_voice_tasks_* serves. Free and internal, so it writes immediately.\n\nMCP: `oxygen_crm_tasks_add`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"assignee":{},"assignee_actor_id":{"type":"string","description":"Workspace member id. Unassigned means the team, not nobody."},"body":{"type":"string","description":"Longer description.","maxLength":20000},"due_at":{"type":"string","description":"ISO-8601 due timestamp. An unparseable value is rejected, never dropped."},"priority":{"type":"string","description":"Manual urgency.","enum":["urgent","high","medium","low"]},"title":{"type":"string","description":"What needs doing.","minLength":1,"maxLength":300}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_tasks_add"]}},"/api/cli/crm/objects/{object}/records/{rowId}/timeline":{"get":{"operationId":"getCrmObjectsObjectRecordsRowIdTimeline","tags":["CRM"],"summary":"CRM Record Timeline","description":"Lists a CRM record's activity timeline (notes, emails, replies, meetings, stage changes, list moves, syncs), newest first, with cursor pagination. Read-only.\n\nMCP: `oxygen_crm_record_timeline`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Pagination cursor from a previous page's next_cursor.","minLength":1,"maxLength":500}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum activities to return. Defaults to 25.","minimum":1,"maximum":100}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_record_timeline"]}},"/api/cli/crm/objects/{object}/relationships":{"post":{"operationId":"postCrmObjectsObjectRelationships","tags":["CRM"],"summary":"Define CRM Relationship","description":"Defines a NEW relationship (and its relation column) from a CUSTOM CRM object to any object, custom or standard — e.g. projects.client -> companies. The source object gets a relation column under the slug; a custom target with inverse_slug gets the inverse relation column too. Cardinality is source:target — one_to_many means each source record links many targets and each target links back to one source (default many_to_many). Once defined, link records with oxygen_crm_relationship_upsert. Standard objects cannot be the SOURCE (their schemas are template-managed).\n\nMCP: `oxygen_crm_relationship_define`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"relationship":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_relationship_define"]}},"/api/cli/crm/photos":{"post":{"operationId":"crm.photos","tags":["CRM"],"summary":"CRM photos","description":"Preview or fill people photos from data this workspace already holds. Free; mode defaults to dry_run.\n\nMCP: `oxygen_crm_photos`, `oxygen_crm_photos_backfill`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["dry_run","live"],"description":"Default dry_run. Inspect preview before live."},"live":{"type":"boolean","description":"Shortcut for mode=live; conflicts with mode=dry_run."},"limit":{"type":"integer","minimum":1,"maximum":10000,"description":"Rows scanned; default 2000."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_photos","oxygen_crm_photos_backfill"]}},"/api/cli/crm/pipeline":{"get":{"operationId":"getCrmPipeline","tags":["CRM"],"summary":"CRM Deal Pipeline","description":"Reads the deals object grouped by pipeline stage (lead → in_progress → won/lost), with per-stage deal counts and amount totals. Seeded sample deals are listed with sample: true but never counted; samples reports them. Read-only.\n\nMCP: `oxygen_crm_pipeline`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum deals to return per stage. Defaults to 200 (also the max).","minimum":1,"maximum":200}},{"name":"pipeline","in":"query","required":false,"schema":{"type":"string","description":"Filter to one pipeline, such as sales, expansion, or renewal.","minLength":1,"maxLength":120}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_pipeline"]}},"/api/cli/crm/records/search":{"post":{"operationId":"postCrmRecordsSearch","tags":["CRM"],"summary":"Search CRM Records","description":"Finds CRM records by normalized identity (domain, email, LinkedIn URL, external ID) or label. Read-only and bounded. mode=suggest is ranked typeahead on a partial string.\n\nMCP: `oxygen_crm_record_search`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Default 20; records max 50, suggest max 25 across all requested objects.","minimum":1,"maximum":50},"mode":{"type":"string","description":"records (default): exact-identity resolve, full row. suggest: ranked typeahead on a fragment of a name, email or domain.","enum":["records","suggest"]},"objectSlugs":{},"object_slugs":{},"objects":{"type":"array","description":"Object slugs; defaults to all.","items":{"type":"string","description":"CRM object slug, e.g. people.","minLength":1,"maxLength":120},"maxItems":20},"q":{},"query":{"type":"string","description":"Identity, label, name, email, or domain.","minLength":1,"maxLength":500},"searchMode":{},"search_mode":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_record_search"]}},"/api/cli/crm/relationships/upsert":{"post":{"operationId":"postCrmRelationshipsUpsert","tags":["CRM"],"summary":"Upsert CRM Relationship","description":"Creates or replaces a CRM relationship edge, such as people.company or companies.team. Defaults to dry_run; pass mode='live' or live=true only after inspecting the preview.\n\nMCP: `oxygen_crm_relationship_upsert`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"live":{"type":"boolean","description":"Same as mode='live'."},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"object":{"type":"string","description":"CRM object slug, e.g. people.","minLength":1,"maxLength":120},"relationship":{"type":"string","description":"Relationship slug from the source object, such as company or team.","minLength":1,"maxLength":120},"role":{"type":"string","description":"Buying-committee role for a deals.stakeholders link: champion, economic_buyer, decision_maker, influencer, or end_user.","minLength":1,"maxLength":60},"row_id":{"type":"string","description":"CRM record row id.","minLength":1,"maxLength":120},"target":{},"targetObject":{},"target_object":{"type":"string","description":"Target CRM object slug. Optional when the relationship definition implies one target object.","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_relationship_upsert"]}},"/api/cli/crm/rollup":{"post":{"operationId":"postCrmRollup","tags":["CRM"],"summary":"Recompute CRM Open Deal Rollup","description":"Recomputes companies.deal_stage (Open Deal: the most advanced OPEN stage among an account's deals, blank once every deal is won or lost) and the copy stamped on its people. It converges on every deal write already — run this to repair after a bulk import, after editing links outside the CRM tools, or on a workspace whose deals predate the column. ZERO CREDITS: a tenant-local join, no provider call. Defaults to dry_run, which counts companies that disagree with their deals and writes nothing.\n\nMCP: `oxygen_crm_rollup`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"includeLifecycle":{},"include_lifecycle":{"type":"boolean","description":"Also recompute Account Stage."},"limit":{"type":"integer","description":"Company rows per sweep. Defaults to 2000.","minimum":1,"maximum":5000},"live":{"type":"boolean","description":"Same as mode='live'."},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"object":{"type":"string","description":"Defaults to companies, the only object today.","enum":["companies"]},"row":{"type":"string","description":"Recompute one company by row id instead of sweeping the object.","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_rollup"]}},"/api/cli/crm/setup":{"post":{"operationId":"postCrmSetup","tags":["CRM"],"summary":"Set Up CRM Objects","description":"Creates or repairs standard CRM object-backed tables and metadata; defaults to dry_run, so pass mode='live' or live=true only after inspecting the plan. A live run that creates the companies or people list also switches on automatic paid enrichment for every record added later: the dry run's preview says what it costs, and without_enrichment=true skips it.\n\nMCP: `oxygen_crm_setup`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"live":{"type":"boolean","description":"Same as mode='live'."},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"objects":{"type":"array","description":"Standard CRM object slugs to set up. Defaults to companies, people, and deals.","items":{"type":"string","description":"CRM object slug, e.g. people.","minLength":1,"maxLength":120},"maxItems":20},"project":{"type":"string","description":"Project id or slug for created CRM tables.","minLength":1,"maxLength":200},"with_enrichment":{"type":"boolean","description":"Also arm the standing cheap-enrichment auto-run on objects that already existed (fresh-created tables arm it by default). New rows then auto-enrich within the per-batch credit cap. Columns the plan's per-record limit leaves out are listed under autoRunColumnsOverLimit."},"without_enrichment":{"type":"boolean","description":"Set up the lists without switching on automatic enrichment, not even on a freshly created table. Wins over with_enrichment."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_setup"]}},"/api/cli/crm/signals":{"post":{"operationId":"postCrmSignals","tags":["CRM"],"summary":"Record CRM GTM Signal","description":"Records one inbound GTM intent signal (website_visit / profile_view / post_engager / new_follower) into the CRM by fanning it into the matching standing signal-touch automation, which asserts the person and logs a timeline activity. Internal CRM write only — free, no approval. Idempotent on external_event_id: pass a stable provider id (e.g. rb2b:<session>) so a redelivery dedupes. Returns the workflow_event_id so an unarmed-template drop (dispatched with zero deliveries) is observable; arm the crm-website-visitor automation first for it to land.\n\nMCP: `oxygen_crm_signal_record`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","description":"Signal event. Slice 1 exercises website_visit.","enum":["website_visit","profile_view","post_engager","new_follower"]},"external_event_id":{"type":"string","description":"Stable provider event id — THE redelivery/idempotency guard. Never random.","minLength":1,"maxLength":500},"metadata":{"type":"object","description":"Optional extra dispatch metadata (provenance).","additionalProperties":true},"payload":{"type":"object","description":"Signal payload: email or linkedin_url (identity), company_domain, company_name, first_name, last_name, page_url, session_id.","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_signal_record"]}},"/api/cli/crm/signals/leads-today":{"get":{"operationId":"getCrmSignalsLeadsToday","tags":["CRM"],"summary":"CRM Leads To Contact Today","description":"Lists people to contact today, ranked by their most recent GTM intent signal (website visit > profile view > post reaction > new follower), dropping terminal-stage and do-not-contact contacts. Read-only. Note: do-not-contact filtering is best-effort — email-only leads (e.g. website-visitor reveals) are surfaced UNCHECKED pending the identity bridge; each lead flags whether it was checked. When the response has rankedBy, equal signals are ordered by the company's ICP fit (each lead's fit names that company).\n\nMCP: `oxygen_crm_signals_today`, `oxygen_signals_leads_today`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum leads to return. Defaults to 25, max 100.","minimum":1,"maximum":100}},{"name":"withinDays","in":"query","required":false,"schema":{}},{"name":"within_days","in":"query","required":false,"schema":{"type":"integer","description":"Signal look-back window in days. Defaults to 7, max 30.","minimum":1,"maximum":30}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_signals_today","oxygen_signals_leads_today"]}},"/api/cli/crm/sync/configure":{"post":{"operationId":"postCrmSyncConfigure","tags":["CRM"],"summary":"Configure CRM Sync","description":"Configures a bidirectional sync between one CRM object (HubSpot contacts|companies, Attio people|companies) and the matching Oxygen object, and writes the standing (provider, object) configuration: direction, per-cycle row cap, and cadence. Conflict rule is most-recent-edit-wins per field. Defaults to dry_run, which returns a REAL preview (bounded candidate count + planned inbound/outbound) by performing a BOUNDED PROVIDER READ (inbound/bidirectional previews pull changed records from the CRM, consuming its API quota) but WITHOUT writing — inspect it first. Configuring is free; running live writes are gated by oxygen_crm_sync_run. If the connection lacks write scope this returns 409 reconnect_required with the missing scopes.\n\nMCP: `oxygen_crm_sync_configure`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{},"cron":{"type":"string","description":"Cron expression for the scheduled cadence, e.g. '*/15 * * * *'. Persisted for the enable lifecycle; defaults to every 15 minutes.","maxLength":120},"direction":{"type":"string","enum":["inbound","outbound","bidirectional"],"description":"Sync direction. Defaults to bidirectional (Attio may be forced outbound if its incremental pull is unavailable)."},"field_mappings":{"type":"array","description":"HubSpot custom-property mappings. Each entry is {oxygen_field, provider_field, direction}; pass [] to clear. Canonical email/domain/name mappings stay fixed.","maxItems":50,"items":{"type":"object","additionalProperties":false,"properties":{"oxygen_field":{"type":"string","minLength":1,"maxLength":128},"provider_field":{"type":"string","minLength":1,"maxLength":128},"direction":{"type":"string","enum":["inbound","outbound","bidirectional"]}},"required":["oxygen_field","provider_field","direction"]}},"live":{"type":"boolean","description":"Shortcut for mode='live' (default dry-run preview)."},"max_credits":{"type":"number","description":"OXYGEN credit ceiling. Workflow steps count after repricing takes effect; provider billing and API quota are separate."},"max_rows_per_cycle":{"type":"integer","description":"Per-cycle row cap — the real volume brake on provider writes.","minimum":1},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"object":{"type":"string","description":"Provider object: hubspot contacts|companies, attio people|companies.","minLength":1},"provider":{"type":"string","enum":["hubspot","attio"],"description":"Connected CRM to sync with."},"timezone":{"type":"string","description":"IANA timezone the cron runs in, e.g. America/New_York. Defaults to UTC.","maxLength":64}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_sync_configure"]}},"/api/cli/crm/sync/disable":{"post":{"operationId":"postCrmSyncDisable","tags":["CRM"],"summary":"Disable Scheduled CRM Sync","description":"Disables the scheduled sync for one (provider, object) pair: stops the cron trigger and revokes the standing write permission so no further scheduled cycle can fire or write. The standing configuration (direction, cadence, mappings, watermarks) is preserved, so re-enabling resumes from the last watermark. Idempotent.\n\nMCP: `oxygen_crm_sync_disable`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","description":"Provider object: hubspot contacts|companies, attio people|companies.","minLength":1},"provider":{"type":"string","enum":["hubspot","attio"],"description":"Connected CRM."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_sync_disable"]}},"/api/cli/crm/sync/enable":{"post":{"operationId":"postCrmSyncEnable","tags":["CRM"],"summary":"Enable Scheduled CRM Sync","description":"Enables scheduled bidirectional CRM sync: arms a cron and standing provider-write permission, then runs an immediate first cycle. Always live; requires approved=true, max_credits and max_rows_per_cycle. First inspect counts via oxygen_crm_sync_configure and current unit prices/cap coverage via oxygen_crm_sync_run (mode='dry_run'). Returns 409 reconnect_required for missing write scope. Disable with oxygen_crm_sync_disable.\n\nMCP: `oxygen_crm_sync_enable`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Confirm enabling scheduled provider writes after inspecting a dry run."},"cron":{"type":"string","description":"Cron expression for the cadence, e.g. '*/15 * * * *'. Defaults to every 15 minutes.","maxLength":120},"direction":{"type":"string","enum":["inbound","outbound","bidirectional"],"description":"Sync direction. Defaults to bidirectional."},"field_mappings":{"type":"array","description":"HubSpot custom-property mappings. Omit to preserve the stored mappings; pass [] to clear.","maxItems":50,"items":{"type":"object","additionalProperties":false,"properties":{"oxygen_field":{"type":"string","minLength":1,"maxLength":128},"provider_field":{"type":"string","minLength":1,"maxLength":128},"direction":{"type":"string","enum":["inbound","outbound","bidirectional"]}},"required":["oxygen_field","provider_field","direction"]}},"max_credits":{"type":"number","description":"OXYGEN credit ceiling. Workflow steps count after repricing takes effect; provider billing and API quota are separate."},"max_rows_per_cycle":{"type":"integer","description":"Per-cycle row cap — the real volume brake on provider writes. Required.","minimum":1},"object":{"type":"string","description":"Provider object: hubspot contacts|companies, attio people|companies.","minLength":1},"provider":{"type":"string","enum":["hubspot","attio"],"description":"Connected CRM to sync with."},"run_now":{"type":"boolean","description":"Run an immediate first cycle after enabling. Defaults to true."},"timezone":{"type":"string","description":"IANA timezone the cron runs in. Defaults to UTC.","maxLength":64}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_sync_enable"]}},"/api/cli/crm/sync/import":{"post":{"operationId":"postCrmSyncImport","tags":["CRM"],"summary":"Import From CRM","description":"Import records from connected HubSpot, Attio or Pipedrive into Oxygen Records. dry_run returns current unit prices with an unknown run total and makes no provider calls. Own-API-key calls incur OXYGEN's current per-call fee; OAuth follows its tool quote. Live Workflow steps cost separately, while row storage is free. Provider billing and API quota are separate. After reviewing the quote and Workflow-step cap coverage, use live with approved=true and max_credits; limit bounds rows. Live queues a durable background Workflow. Read its outcome before treating records as imported; oxygen_crm_sync_links shows provider-id provenance.\n\nMCP: `oxygen_crm_sync_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Confirm a live import after inspecting a dry run."},"into":{"type":"string","description":"Oxygen CRM object slug to import into. Defaults to the natural mapping."},"limit":{"type":"integer","description":"Max records to pull this run.","minimum":1},"live":{"type":"boolean","description":"Shortcut for mode='live'."},"max_credits":{"type":"number","description":"OXYGEN credit ceiling. Workflow steps count after repricing takes effect; provider billing and API quota are separate."},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"object":{"type":"string","description":"Provider object: hubspot contacts|companies, attio people|companies, pipedrive persons|organizations|deals. Import Pipedrive persons and organizations before deals so each deal links to them.","minLength":1},"provider":{"type":"string","enum":["hubspot","attio","pipedrive"],"description":"Connected CRM to import from."},"types":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_sync_import"]}},"/api/cli/crm/sync/links":{"get":{"operationId":"getCrmSyncLinks","tags":["CRM"],"summary":"List CRM Sync Links","description":"Lists the external provider-id registry for one CRM record — which HubSpot/Attio/Pipedrive external ids are mapped to this Oxygen record (the import/sync provenance).\n\nMCP: `oxygen_crm_sync_links`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"query","required":false,"schema":{"type":"string","description":"CRM object slug, e.g. people.","minLength":1,"maxLength":120}},{"name":"rowId","in":"query","required":false,"schema":{}},{"name":"row_id","in":"query","required":false,"schema":{"type":"string","description":"CRM record row id.","minLength":1,"maxLength":120}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_sync_links"]}},"/api/cli/crm/sync/run":{"post":{"operationId":"postCrmSyncRun","tags":["CRM"],"summary":"Run CRM Sync Cycle","description":"Run one CRM reconciliation cycle: pull provider changes and push changed Oxygen rows, using most-recent-edit-wins without echo loops. dry_run makes no provider calls and returns current unit prices, Workflow-step cap coverage and an unknown run total. Provider billing and API quota apply separately. After reviewing, live requires approved=true and max_credits. It queues a durable Workflow; oxygen_crm_sync_status shows the outcome and oxygen_crm_sync_links shows provider-id provenance.\n\nMCP: `oxygen_crm_sync_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Confirm a live cycle after inspecting a dry run."},"configId":{},"config_id":{"type":"string","description":"Standing sync configuration to use."},"direction":{"type":"string","enum":["inbound","outbound","bidirectional"],"description":"Override the configured direction for this cycle. Defaults to the standing configuration."},"live":{"type":"boolean","description":"Shortcut for mode='live' (default dry-run plan)."},"max_credits":{"type":"number","description":"OXYGEN credit ceiling. Workflow steps count after repricing takes effect; provider billing and API quota are separate."},"max_rows_per_cycle":{"type":"integer","description":"Per-cycle row cap for this run — the real volume brake on provider writes.","minimum":1},"mode":{"type":"string","description":"dry_run by default; inspect it before live.","enum":["dry_run","live"]},"object":{"type":"string","description":"Provider object: hubspot contacts|companies, attio people|companies.","minLength":1},"provider":{"type":"string","enum":["hubspot","attio"],"description":"Connected CRM to reconcile with."},"since":{"type":"string","description":"Provider change watermark for this cycle."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_sync_run"]}},"/api/cli/crm/sync/status":{"get":{"operationId":"getCrmSyncStatus","tags":["CRM"],"summary":"CRM Sync Status","description":"Reads CRM sync status, newest cycle first. Pass provider + object for the standing (provider, object) configuration: direction, cadence, enabled flag, per-direction watermarks, and last-cycle counts. Or pass run_id to read one durable cycle's run status and pulled/created/updated/skipped counts. Provide exactly one of (provider + object) or run_id. Read-only.\n\nMCP: `oxygen_crm_sync_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"object","in":"query","required":false,"schema":{"type":"string","description":"Provider object whose standing sync config to read. Pair with provider.","minLength":1}},{"name":"provider","in":"query","required":false,"schema":{"type":"string","enum":["hubspot","attio"],"description":"Connected CRM whose standing sync config to read. Pair with object."}},{"name":"runId","in":"query","required":false,"schema":{}},{"name":"run_id","in":"query","required":false,"schema":{"type":"string","description":"A sync cycle run id to read instead of the standing config.","minLength":1,"maxLength":120}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_sync_status"]}},"/api/cli/crm/tasks":{"get":{"operationId":"crm.tasks.list","tags":["CRM"],"summary":"CRM tasks list","description":"Read the workspace task queue by status, assignee and cursor.\n\nMCP: `oxygen_crm_tasks_list`, `oxygen_crm_tasks_queue`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","completed","cancelled","all",""],"description":"open, completed or cancelled; all, empty or omitted reads every status."}},{"name":"assignee","in":"query","required":false,"schema":{"type":"string","description":"Workspace scope only: member email, user id, or me."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Maximum tasks; the server clamps to 200. Default 50."}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Previous nextCursor; empty is ignored."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_crm_tasks_list","oxygen_crm_tasks_queue"]}},"/api/cli/crm/tasks/{taskId}":{"patch":{"operationId":"patchCrmTasksTaskId","tags":["CRM"],"summary":"Update CRM Task","description":"Completes, reopens, reassigns or re-dates a CRM task. Re-completing a completed task keeps its original completion time and adds no second timeline entry.\n\nMCP: `oxygen_crm_tasks_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"taskId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"assignee":{},"assignee_actor_id":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"Workspace member id or email; null unassigns."},"body":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"Replacement description; null clears."},"due_at":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"ISO-8601 deadline; null clears."},"priority":{"oneOf":[{"type":"string","enum":["urgent","high","medium","low"]},{"type":"null"}],"description":"Manual urgency; null clears."},"status":{"type":"string","description":"New status.","enum":["open","completed","cancelled"]},"title":{"type":"string","description":"Replacement title.","maxLength":300}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_crm_tasks_update"]}},"/api/cli/custom-integrations":{"get":{"operationId":"getCustomIntegrations","tags":["Custom integrations"],"summary":"List Custom HTTP Integrations","description":"Lists custom HTTP tool integrations registered for the active organization — slug, name, auth type, base URL, and the generated custom_http.* tool ids. Pass slug to filter to one integration. Read-only; routes through GET /api/cli/custom-integrations.\n\nMCP: `oxygen_custom_integrations_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"query","required":false,"schema":{"type":"string","description":"Filter to one custom integration slug, e.g. 'acme_crm'. Omit to list every custom HTTP integration for the active organization. Hyphenated manifest slugs are stored as canonical snake_case slugs.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_custom_integrations_list"]},"post":{"operationId":"postCustomIntegrations","tags":["Custom integrations"],"summary":"Apply Custom HTTP Integration","description":"Creates or updates a custom HTTP tool integration from a manifest, registering its operations as custom_http.* tools in the catalog. State-changing but not paid/live: it saves the manifest and performs no external provider call itself. Credentials are rejected here; use oxygen_custom_integration_connect. Routes through POST /api/cli/custom-integrations.\n\nMCP: `oxygen_custom_integrations_apply`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"manifest":{"type":"object","description":"Custom HTTP integration manifest (version 1). Required keys: version (1), slug, name, description, baseUrl, auth, operations[]. Do NOT include credentials or API keys — they are rejected; store them with oxygen_custom_integration_connect.","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_custom_integrations_apply"]}},"/api/cli/custom-integrations/connect":{"post":{"operationId":"integrations.custom.connect","tags":["Custom integrations"],"summary":"Custom integrations connect","description":"Store an encrypted API key for an applied custom HTTP integration; the secret is never returned.\n\nMCP: `oxygen_custom_integration_connect`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"api_key":{"type":"string"}},"required":["slug","api_key"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_custom_integration_connect"]}},"/api/cli/custom-integrations/remove":{"post":{"operationId":"postCustomIntegrationsRemove","tags":["Custom integrations"],"summary":"Remove Custom HTTP Integration","description":"Preview removing one custom HTTP integration, its stored credential and catalog tools. Confirm with approved and the returned plan_hash. Columns, workflows and history remain; bound callers stop working.\n\nMCP: `oxygen_custom_integrations_remove`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"connection_id":{"type":"string","description":"Exact connection id; choose this if a slug is ambiguous."},"plan_hash":{"type":"string","description":"Hash from the exact removal preview."},"slug":{"type":"string","description":"Custom integration slug. Supply slug or connection_id; both must select the same connection.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_custom_integrations_remove"]}},"/api/cli/dashboards":{"get":{"operationId":"getDashboards","tags":["Dashboards"],"summary":"List Dashboards","description":"Lists the workspace's saved dashboards — the user-defined ones in the CRM, not the built-in Command Center funnel. Read-only.\n\nMCP: `oxygen_dashboards_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tag","in":"query","required":false,"schema":{"type":"string","description":"Optional workspace tag filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_dashboards_list"]},"post":{"operationId":"postDashboards","tags":["Dashboards"],"summary":"Create Dashboard","description":"Creates a saved dashboard in the CRM with one empty tab. Add widgets with oxygen_dashboards_widget_add. No credits.\n\nMCP: `oxygen_dashboards_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string","description":"What it answers."},"icon":{"type":"string","description":"Sidebar icon name."},"isDefault":{},"is_default":{"type":"boolean","description":"Open this one by default."},"name":{"type":"string","description":"Display name."},"slug":{"type":"string","description":"Stable dashboard URL slug."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_dashboards_create"]}},"/api/cli/dashboards/{dashboardId}":{"get":{"operationId":"getDashboardsDashboardId","tags":["Dashboards"],"summary":"Get Dashboard","description":"Reads one saved dashboard with its tabs and widget configurations. Read-only.\n\nMCP: `oxygen_dashboards_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_dashboards_get"]},"patch":{"operationId":"patchDashboardsDashboardId","tags":["Dashboards"],"summary":"Update Dashboard","description":"Renames a saved dashboard or changes its description, icon or default flag. No credits.\n\nMCP: `oxygen_dashboards_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string","description":"New description; empty clears."},"icon":{"type":"string","description":"New icon name."},"isDefault":{},"is_default":{"type":"boolean","description":"Make this the default."},"name":{"type":"string","description":"New display name."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_dashboards_update"]},"delete":{"operationId":"deleteDashboardsDashboardId","tags":["Dashboards"],"summary":"Delete Dashboard","description":"Archives a saved dashboard. The definition is kept, the slug becomes reusable, and the data it reported on is untouched.\n\nMCP: `oxygen_dashboards_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_dashboards_delete"]}},"/api/cli/dashboards/{dashboardId}/tabs":{"post":{"operationId":"dashboards.tabs.create","tags":["Dashboards"],"summary":"Dashboards tabs add","description":"Create a named tab in a workspace dashboard.\n\nMCP: `oxygen_dashboard_tab_create`, `oxygen_dashboards_tab_add`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"}},"required":["title"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_dashboard_tab_create","oxygen_dashboards_tab_add"]},"delete":{"operationId":"dashboards.tabs.delete","tags":["Dashboards"],"summary":"Dashboards tabs remove","description":"Remove one dashboard tab by its id.\n\nMCP: `oxygen_dashboard_tab_delete`, `oxygen_dashboards_tab_remove`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}},{"name":"tab","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_dashboard_tab_delete","oxygen_dashboards_tab_remove"]}},"/api/cli/dashboards/{dashboardId}/tags":{"post":{"operationId":"postDashboardsDashboardIdTags","tags":["Dashboards"],"summary":"Tag a Definition","description":"Replaces workspace tags on one Signal type, saved Dashboard, runtime Agent, or saved Ads search. This is metadata only and never runs a provider.\n\nMCP: `oxygen_tags_attach`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"},"description":"The complete tag list; [] clears."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tags_attach"]}},"/api/cli/dashboards/{dashboardId}/widgets":{"post":{"operationId":"postDashboardsDashboardIdWidgets","tags":["Dashboards"],"summary":"Add Dashboard Widget","description":"Adds a widget to a saved dashboard. Call oxygen_dashboards_widget_kinds first for each kind's configuration shape. Adding costs nothing; only a live_source widget can later cost credits, bounded by its own maxCredits.\n\nMCP: `oxygen_dashboards_widget_add`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"configuration":{"type":"object","description":"Kind-specific configuration."},"kind":{"type":"string","description":"Widget kind.","enum":["chart","view","iframe","rich_text","code","live_source","deliverability_evidence"]},"position":{"type":"object","description":"Grid placement {x,y,w,h}, 12 columns."},"tab":{"type":"string","description":"Tab id; defaults to the first."},"tab_id":{},"title":{"type":"string","description":"Widget title."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_dashboards_widget_add"]},"patch":{"operationId":"patchDashboardsDashboardIdWidgets","tags":["Dashboards"],"summary":"Update Dashboard Widget","description":"Changes a widget's title, configuration or placement, or pauses/resumes a live_source. A configuration REPLACES the previous one, never merges. Pausing revokes a live source's standing permission to spend.\n\nMCP: `oxygen_dashboards_widget_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"configuration":{"type":"object","description":"Replacement configuration."},"isPaused":{},"is_paused":{"type":"boolean","description":"Pause or resume a live source."},"position":{"type":"object","description":"New grid placement {x,y,w,h}."},"title":{"type":"string","description":"New title."},"widget":{"type":"string","description":"Widget id."},"widget_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_dashboards_widget_update"]},"delete":{"operationId":"deleteDashboardsDashboardIdWidgets","tags":["Dashboards"],"summary":"Remove Dashboard Widget","description":"Removes a widget from a saved dashboard. The data it reported on is untouched.\n\nMCP: `oxygen_dashboards_widget_remove`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}},{"name":"widget","in":"query","required":false,"schema":{"type":"string","description":"Widget id."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_dashboards_widget_remove"]}},"/api/cli/dashboards/{dashboardId}/widgets/{widgetId}/data":{"get":{"operationId":"getDashboardsDashboardIdWidgetsWidgetIdData","tags":["Dashboards"],"summary":"Read Dashboard Widget Data","description":"Reads the data behind one widget — the same numbers the web page draws. A live_source serves its cached result and never fetches here. Read-only, no credits.\n\nMCP: `oxygen_dashboards_widget_data`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}},{"name":"widgetId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_dashboards_widget_data"]}},"/api/cli/dashboards/{dashboardId}/widgets/{widgetId}/refresh":{"post":{"operationId":"postDashboardsDashboardIdWidgetsWidgetIdRefresh","tags":["Dashboards"],"summary":"Refresh Dashboard Widget","description":"Refreshes a live_source widget now, calling its external tool. THE ONLY dashboard call that can cost credits — bounded by the ceiling saved on the widget, and refused while it is paused. Reading a dashboard never spends.\n\nMCP: `oxygen_dashboards_widget_refresh`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"dashboardId","in":"path","required":true,"schema":{"type":"string"}},{"name":"widgetId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_dashboards_widget_refresh"]}},"/api/cli/dashboards/summary":{"get":{"operationId":"getDashboardsSummary","tags":["Dashboards"],"summary":"GTM Dashboard Summary","description":"Reads the GTM funnel: outbound touches → replies → positive replies across email, LinkedIn and WhatsApp → meetings → deals → won; revenue, channel split, lifecycle funnels and current triage. Read-only. Funnel and revenue count window co-occurrence, not cohort attribution. Triage is current: unread conversations across channels and interested email conversations are independent of the selected range; mailbox attention counts sending-breaker pauses.\n\nMCP: `oxygen_dashboard_summary`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"cold_days","in":"query","required":false,"schema":{}},{"name":"cold_deal_days","in":"query","required":false,"schema":{"type":"integer","description":"Days of no activity before an open deal counts as 'cold' in the triage strip. Defaults to 14.","minimum":1,"maximum":365}},{"name":"from","in":"query","required":false,"schema":{"type":"string","description":"Custom start date (YYYY-MM-DD). Pair with range=custom or to."}},{"name":"range","in":"query","required":false,"schema":{"type":"string","description":"Preset window: 7d, 14d, 28d, or 30d. Defaults to 14d. Use from/to for a custom range.","enum":["7d","14d","28d","30d","custom"]}},{"name":"to","in":"query","required":false,"schema":{"type":"string","description":"Custom end date (YYYY-MM-DD)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_dashboard_summary"]}},"/api/cli/dashboards/widget-kinds":{"get":{"operationId":"getDashboardsWidgetKinds","tags":["Dashboards"],"summary":"Dashboard Widget Kinds","description":"Lists every dashboard widget kind with an example configuration and whether it can cost credits. Read this before building a widget. Read-only.\n\nMCP: `oxygen_dashboards_widget_kinds`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_dashboards_widget_kinds"]}},"/api/cli/db/attach":{"post":{"operationId":"db.attach","tags":["DB"],"summary":"DB attach","description":"Attach an owned PostgreSQL database and initialize this workspace's schema/roles immediately. Changes the workspace database; no preview or confirmation field. Native workspace write access applies. Use Supabase import tools for external Tables. 0 credits.\n\nMCP: `oxygen_database_attach`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"database_url":{"type":"string","minLength":1,"description":"Owner PostgreSQL URL for a database you own; attaches and initializes it immediately."}},"required":["database_url"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_database_attach"]}},"/api/cli/db/cost-policy":{"get":{"operationId":"db.cost_policy.get","tags":["DB"],"summary":"DB cost policy","description":"Read this workspace's retired Neon cost-policy status. PostgreSQL has no per-workspace sleep control; stored Neon policy is historical. 0 credits.\n\nMCP: `oxygen_database_cost_policy`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_database_cost_policy"]}},"/api/cli/db/migrate":{"post":{"operationId":"db.migrate","tags":["DB"],"summary":"DB migrate","description":"Apply pending workspace database migrations immediately; optionally repair runtime/read passwords. Read oxygen_workspace_database_status first. No preview or confirmation field; native workspace write access applies. Fleet repair remains separate. 0 credits.\n\nMCP: `oxygen_database_migrate`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rotate_credentials":{"type":"boolean","description":"Repair runtime/read passwords and stored credentials. Omitted/false keeps them; routine migrations do not need rotation."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_database_migrate"]}},"/api/cli/db/provision":{"post":{"operationId":"db.provision","tags":["DB"],"summary":"DB provision","description":"Provision or retry this workspace database immediately; already-ready workspaces retain it. No preview or confirmation field; native workspace write access applies. May outlast the connector deadline: read oxygen_workspace_database_status before retrying. Hosting is plan-included; 0 credits.\n\nMCP: `oxygen_workspace_database_provision`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workspace_database_provision"]}},"/api/cli/db/query":{"post":{"operationId":"db.query","tags":["DB"],"summary":"DB query","description":"Read this workspace's database with one bounded SQL statement. Complete rows, default 20, maximum 1000; writes refused. On truncation, narrow SELECT/WHERE or use your own stable ORDER BY/keyset predicate; no server cursor. 0 credits.\n\nMCP: `oxygen_database_query`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sql":{"type":"string","minLength":1,"description":"One SELECT, WITH or EXPLAIN statement; read-only transaction, dedicated customer login, default 5-second timeout."},"max_rows":{"type":"integer","minimum":1,"maximum":1000,"x-clamp":true,"description":"CLI/API default 100; MCP default 20; hard cap 1000."},"max_chars":{"type":"integer","minimum":1000,"maximum":48000,"description":"Optional complete-row response window including metadata. MCP caps at 10000 chars, built-in agents 4000. Narrow SELECT if one row cannot fit."}},"required":["sql"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_database_query"]}},"/api/cli/db/reconcile-cost-policy":{"post":{"operationId":"db.cost_policy.reconcile","tags":["DB"],"summary":"DB reconcile cost policy","description":"Retired Neon compatibility action: reports applied=false with no operations; does not suspend PostgreSQL. Native workspace write access applies; no preview or confirmation field. 0 credits.\n\nMCP: `oxygen_database_cost_policy_reconcile`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"suspend_idle":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_database_cost_policy_reconcile"]}},"/api/cli/db/status":{"get":{"operationId":"db.status","tags":["DB"],"summary":"DB status","description":"Read this workspace's database status and latest completed provisioning/migration receipt; not a list of current pending migrations. Historical Neon fields are lineage. Hosting is plan-included; 0 credits.\n\nMCP: `oxygen_workspace_database_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_database_status"]}},"/api/cli/deliverability/checks":{"get":{"operationId":"getDeliverabilityChecks","tags":["Deliverability"],"summary":"List Deliverability Checks","description":"Stored check runs newest first (DNS auth, BIMI, tracking CNAME, blacklist, copy score, header proof) with finding counts. Runs no check, 0 credits. Placement probes: oxygen_mailboxes_deliverability_observations_list.\n\nMCP: `oxygen_mailboxes_deliverability_checks_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_checks_list"]}},"/api/cli/deliverability/checks/{id}":{"get":{"operationId":"getDeliverabilityChecksId","tags":["Deliverability"],"summary":"Get Deliverability Check","description":"One stored check run: every finding worst first, with values and bounded raw evidence. 0 credits.\n\nMCP: `oxygen_mailboxes_deliverability_checks_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_checks_get"]}},"/api/cli/deliverability/compare":{"get":{"operationId":"getDeliverabilityCompare","tags":["Deliverability"],"summary":"Compare Deliverability Runs","description":"Diff two stored runs of one kind: placement tests (workspace or placement test ids) by receiver provider with sample sizes, copy, rule and domain-check changes; or two check runs finding by finding. 0 credits.\n\nMCP: `oxygen_mailboxes_deliverability_compare`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_compare"]}},"/api/cli/deliverability/evidence":{"get":{"operationId":"getDeliverabilityEvidence","tags":["Deliverability"],"summary":"Deliverability Evidence","description":"What changed and what placement did for one sender domain, mailbox, copy hash or receiver provider: placement by UTC bucket and provider, DNS/BIMI/blacklist state and changes, copy scores, campaign outcomes, Signals. Rates carry sample sizes; default last 28 days by day. 0 credits.\n\nMCP: `oxygen_mailboxes_deliverability_evidence`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_evidence"]}},"/api/cli/deliverability/observations":{"get":{"operationId":"getDeliverabilityObservations","tags":["Deliverability"],"summary":"List Placement Observations","description":"Stored inbox-placement probes newest first by placement time (sent, else observed): folder, tab, receiver provider, SPF/DKIM/DMARC proof and copy hash, from workspace, network and placement tests. 0 credits.\n\nMCP: `oxygen_mailboxes_deliverability_observations_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_observations_list"]}},"/api/cli/deliverability/placement-tests":{"get":{"operationId":"getDeliverabilityPlacementTests","tags":["Deliverability"],"summary":"List Inbox-Placement Tests","description":"Directional history: view=summary, filter status, follow next_cursor until null. count=page; total/status_counts=all matches. creditsUsed=recorded cost; refund=restoration, not wallet spend. Active reads may refresh upstream.\n\nMCP: `oxygen_placement_tests_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_placement_tests_list"]},"post":{"operationId":"postDeliverabilityPlacementTests","tags":["Deliverability"],"summary":"Run Inbox-Placement Test","description":"Free directional preview returns provider, cost and plan_hash. Approve with max_credits. OXYGEN deliverability creates seeds; separately approve send. Zapmail owns delivery. OXYGEN placement evaluation: limited pilot, one 0-credit test for its enabled sender; requires subject/body_text. Approval creates and sends its probe. Poll oxygen_placement_tests_get.\n\nMCP: `oxygen_placement_tests_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_paused_probe":{"type":"boolean","description":"OXYGEN deliverability paused probe: opt in at create AND send; keeps pauses/caps, blocks disabled."},"approved":{"type":"boolean","description":"true executes; otherwise preview."},"body_text":{"type":"string","description":"Plain-text seed body; required for OXYGEN evaluation, ignored by Zapmail."},"mailbox":{"type":"string","description":"Connected sending mailbox address."},"max_credits":{"type":"number","description":"Accepted cap, at least credits_required."},"plan_hash":{"type":"string","description":"Fresh preview hash required to approve."},"provider":{"type":"string","enum":["oxygen_deliverability","zapmail","oxygen_placement"],"description":"Default OXYGEN deliverability/Zapmail; evaluation requires its enabled pilot sender."},"subject":{"type":"string","description":"Seed subject; required for OXYGEN evaluation. Zapmail uses it as a label."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_placement_tests_run"]}},"/api/cli/deliverability/placement-tests/{id}":{"get":{"operationId":"getDeliverabilityPlacementTestsId","tags":["Deliverability"],"summary":"Get Inbox-Placement Test","description":"Seeds/results; active tests may refresh upstream. creditsUsed=recorded cost; results.refund=restoration, not wallet spend. Pilot summary units unverified.\n\nMCP: `oxygen_placement_tests_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_placement_tests_get"]}},"/api/cli/deliverability/placement-tests/{id}/send":{"post":{"operationId":"postDeliverabilityPlacementTestsIdSend","tags":["Deliverability"],"summary":"Send OXYGEN deliverability Placement Probe","description":"Free OXYGEN deliverability preview shows exact sender, transport, all seeds, content and plan_hash. Approve that hash to queue one message for 0 extra credits. Ambiguous delivery is never retried. Zapmail owns its delivery.\n\nMCP: `oxygen_placement_tests_send`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_paused_probe":{"type":"boolean","description":"OXYGEN deliverability paused probe: opt in at create AND send; keeps pauses/caps, blocks disabled."},"approved":{"type":"boolean","description":"true sends; otherwise exact preview."},"plan_hash":{"type":"string","description":"Hash from a fresh send preview; required with approved=true."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_placement_tests_send"]}},"/api/cli/deliverability/score-copy":{"post":{"operationId":"postDeliverabilityScoreCopy","tags":["Deliverability"],"summary":"Score Email Copy","description":"Score one email copy for spam-filter content signals on OXYGEN's own scorer; stores a copy-score check run (content hash, score, rules, link domains). Sends nothing, 0 credits.\n\nMCP: `oxygen_mailboxes_deliverability_score_copy`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","description":"Sender address (default sender@example.com)."},"request_id":{"type":"string","description":"Retry key; unchanged copy returns its stored score."},"subject":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_score_copy"]}},"/api/cli/deliverability/workspace-tests":{"get":{"operationId":"getDeliverabilityWorkspaceTests","tags":["Deliverability"],"summary":"Deliverability Test Results","description":"Read saved deliverability testing history/results; mode=bulk selects all-mailbox batches. Follow cursor; probe_id/body_part/offset reads frozen copy. action=copy reads Sequence copy. Staff action=receivers discovers inboxes by receiver_environment/receiver_workspace_id/query. No send or refresh.\n\nMCP: `oxygen_workspace_placement_read`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_placement_read"]},"post":{"operationId":"postDeliverabilityWorkspaceTests","tags":["Deliverability"],"summary":"Deliverability Testing","description":"Preview deliverability testing across Google/Microsoft inboxes; mode=bulk tests all eligible mailboxes using own receivers, default both providers. Realistic Sequence/prospect copy only. 0 additional credits; approved sends real mail. Review all preview cursors/copy offsets; reuse input/request_id/plan_hash/rendered_at and exact max_live_sends. Five variants, 50 messages per child; bulk can exceed 50. Single mode needs sender/receiver IDs or receiver_scope=network; staff can name receiver_environment/receiver_workspace_id with receiver_scope=staff. operation=participation manages receiving (admin). Copy reaches other inboxes; no campaign resume.\n\nMCP: `oxygen_workspace_placement_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"accept_network_disclosure":{"type":"boolean"},"allow_daily_limit_override":{"type":"boolean","description":"Staff single mode: exact daily quota exception, one diagnostic per sender."},"allow_paused_probe":{"type":"boolean"},"approved":{"type":"boolean"},"max_live_sends":{"type":"integer","minimum":1},"network_enabled":{"type":"boolean"},"operation":{"type":"string","enum":["test","participation"]},"plan_hash":{"type":"string"},"preview_copy_limit":{"type":"integer","minimum":1,"maximum":3000},"preview_cursor":{"type":"string"},"preview_limit":{"type":"integer","minimum":1,"maximum":20},"preview_offset":{"type":"integer","minimum":0},"preview_part":{"type":"string","enum":["body_text","body_html"]},"preview_probe_id":{"type":"string"},"preview_skipped_cursor":{"type":"string"},"receiver_environment":{"type":"string","enum":["dev","prod"]},"receiver_mailbox_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50},"receiver_providers":{"type":"array","items":{"type":"string","enum":["google","microsoft"]},"minItems":1,"maxItems":2},"receiver_scope":{"type":"string","enum":["workspace","network","staff"]},"receiver_workspace_id":{"type":"string"},"rendered_at":{"type":"string"},"request_id":{"type":"string"},"sender_mailbox_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50},"tracking_clicks":{"type":"boolean"},"tracking_opens":{"type":"boolean"},"variants":{"type":"array","minItems":1,"maxItems":5,"items":{"type":"object","properties":{"key":{"type":"string"},"subject":{"type":"string"},"body_text":{"type":"string"},"body_html":{"type":"string"}},"required":["key","subject","body_text"],"additionalProperties":false}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workspace_placement_run"]}},"/api/cli/deliverability/workspace-tests/{id}":{"get":{"operationId":"getDeliverabilityWorkspaceTestsId","tags":["Deliverability"],"summary":"Deliverability Test Results","description":"Read saved deliverability testing history/results; mode=bulk selects all-mailbox batches. Follow cursor; probe_id/body_part/offset reads frozen copy. action=copy reads Sequence copy. Staff action=receivers discovers inboxes by receiver_environment/receiver_workspace_id/query. No send or refresh.\n\nMCP: `oxygen_workspace_placement_read`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_placement_read"]}},"/api/cli/deliverability/workspace-tests/bulk":{"get":{"operationId":"getDeliverabilityWorkspaceTestsBulk","tags":["Deliverability"],"summary":"Deliverability Test Results","description":"Read saved deliverability testing history/results; mode=bulk selects all-mailbox batches. Follow cursor; probe_id/body_part/offset reads frozen copy. action=copy reads Sequence copy. Staff action=receivers discovers inboxes by receiver_environment/receiver_workspace_id/query. No send or refresh.\n\nMCP: `oxygen_workspace_placement_read`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_placement_read"]},"post":{"operationId":"postDeliverabilityWorkspaceTestsBulk","tags":["Deliverability"],"summary":"Deliverability Testing","description":"Preview deliverability testing across Google/Microsoft inboxes; mode=bulk tests all eligible mailboxes using own receivers, default both providers. Realistic Sequence/prospect copy only. 0 additional credits; approved sends real mail. Review all preview cursors/copy offsets; reuse input/request_id/plan_hash/rendered_at and exact max_live_sends. Five variants, 50 messages per child; bulk can exceed 50. Single mode needs sender/receiver IDs or receiver_scope=network; staff can name receiver_environment/receiver_workspace_id with receiver_scope=staff. operation=participation manages receiving (admin). Copy reaches other inboxes; no campaign resume.\n\nMCP: `oxygen_workspace_placement_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"accept_network_disclosure":{"type":"boolean"},"allow_daily_limit_override":{"type":"boolean","description":"Staff single mode: exact daily quota exception, one diagnostic per sender."},"allow_paused_probe":{"type":"boolean"},"approved":{"type":"boolean"},"max_live_sends":{"type":"integer","minimum":1},"network_enabled":{"type":"boolean"},"operation":{"type":"string","enum":["test","participation"]},"plan_hash":{"type":"string"},"preview_copy_limit":{"type":"integer","minimum":1,"maximum":3000},"preview_cursor":{"type":"string"},"preview_limit":{"type":"integer","minimum":1,"maximum":20},"preview_offset":{"type":"integer","minimum":0},"preview_part":{"type":"string","enum":["body_text","body_html"]},"preview_probe_id":{"type":"string"},"preview_skipped_cursor":{"type":"string"},"receiver_environment":{"type":"string","enum":["dev","prod"]},"receiver_mailbox_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50},"receiver_providers":{"type":"array","items":{"type":"string","enum":["google","microsoft"]},"minItems":1,"maxItems":2},"receiver_scope":{"type":"string","enum":["workspace","network","staff"]},"receiver_workspace_id":{"type":"string"},"rendered_at":{"type":"string"},"request_id":{"type":"string"},"sender_mailbox_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50},"tracking_clicks":{"type":"boolean"},"tracking_opens":{"type":"boolean"},"variants":{"type":"array","minItems":1,"maxItems":5,"items":{"type":"object","properties":{"key":{"type":"string"},"subject":{"type":"string"},"body_text":{"type":"string"},"body_html":{"type":"string"}},"required":["key","subject","body_text"],"additionalProperties":false}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workspace_placement_run"]}},"/api/cli/deliverability/workspace-tests/bulk/{id}":{"get":{"operationId":"getDeliverabilityWorkspaceTestsBulkId","tags":["Deliverability"],"summary":"Deliverability Test Results","description":"Read saved deliverability testing history/results; mode=bulk selects all-mailbox batches. Follow cursor; probe_id/body_part/offset reads frozen copy. action=copy reads Sequence copy. Staff action=receivers discovers inboxes by receiver_environment/receiver_workspace_id/query. No send or refresh.\n\nMCP: `oxygen_workspace_placement_read`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_placement_read"]}},"/api/cli/deliverability/workspace-tests/copy":{"get":{"operationId":"getDeliverabilityWorkspaceTestsCopy","tags":["Deliverability"],"summary":"Deliverability Test Results","description":"Read saved deliverability testing history/results; mode=bulk selects all-mailbox batches. Follow cursor; probe_id/body_part/offset reads frozen copy. action=copy reads Sequence copy. Staff action=receivers discovers inboxes by receiver_environment/receiver_workspace_id/query. No send or refresh.\n\nMCP: `oxygen_workspace_placement_read`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_placement_read"]}},"/api/cli/directory/apply":{"post":{"operationId":"directory.apply","tags":["Directory"],"summary":"Directory apply","description":"Apply for an agency-directory listing for this workspace; reuses an existing open application.\n\nMCP: `oxygen_directory_apply`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"website":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_directory_apply"]}},"/api/cli/directory/listing":{"get":{"operationId":"getDirectoryListing","tags":["Directory"],"summary":"Get Agency Directory Listing","description":"Reads this organization's agency directory listing: profile fields, publish status (invited/published/delisted), and public/settings deep-links. Fails with directory_not_enabled when the org has not been invited to the directory. Read-only.\n\nMCP: `oxygen_directory_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_directory_get"]}},"/api/cli/directory/listing/logo":{"post":{"operationId":"directory.logo","tags":["Directory"],"summary":"Directory logo upload","description":"Upload a public agency-directory logo and read back the updated listing; PNG, JPEG, WebP or SVG, at most 2 MB.\n\nCLI: `oxygen directory logo upload`.\n\nMCP: `oxygen_directory_logo_upload`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"content_base64":{"type":"string"},"file_name":{"type":"string"},"content_type":{"type":"string","enum":["image/png","image/jpeg","image/webp","image/svg+xml"]}},"required":["content_base64","file_name","content_type"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_directory_logo_upload"],"x-oxygen-cli-command":"oxygen directory logo upload"}},"/api/cli/directory/listing/publish":{"post":{"operationId":"postDirectoryListingPublish","tags":["Directory"],"summary":"Publish Agency Directory Listing","description":"Publishes this organization's listing to the public agency directory (a public web page — confirm with the user first). Requires a tagline, a description, and at least one contact method. Returns the public_url deep-link.\n\nMCP: `oxygen_directory_publish`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_directory_publish"]}},"/api/cli/directory/listing/unpublish":{"post":{"operationId":"postDirectoryListingUnpublish","tags":["Directory"],"summary":"Unpublish Agency Directory Listing","description":"Removes this organization's listing from the public agency directory. The draft stays editable and can be re-published later.\n\nMCP: `oxygen_directory_unpublish`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_directory_unpublish"]}},"/api/cli/directory/listing/update":{"post":{"operationId":"postDirectoryListingUpdate","tags":["Directory"],"summary":"Update Agency Directory Listing","description":"Updates this organization's agency directory profile (name, tagline, plain-text description, logo URL, website, company LinkedIn, founding team with per-founder LinkedIn URLs, booking link, contact email, and curated services/regions multi-selects). Changes to a published listing go live immediately.\n\nMCP: `oxygen_directory_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"featured":{},"founders":{},"profile":{"type":"object","description":"Listing profile fields to set. A key that is present is applied (null clears it); absent keys stay unchanged.","properties":{"name":{"type":"string","description":"Agency display name."},"slug":{"type":"string","description":"Public URL slug (lowercase letters, digits, dashes)."},"logo_url":{"type":"string","description":"Logo image URL."},"tagline":{"type":"string","description":"One-line pitch shown on the directory card."},"description":{"type":"string","description":"Full profile description. Plain text — blank lines separate paragraphs; markdown is not rendered."},"website_url":{"type":"string","description":"Company website URL."},"linkedin_company_url":{"type":"string","description":"Company LinkedIn page URL."},"founders":{"type":"array","description":"Founding team shown on the public profile.","items":{"type":"object","properties":{"name":{"type":"string","description":"Founder name."},"title":{"type":"string","description":"Role, e.g. Co-founder & CEO."},"linkedin_url":{"type":"string","description":"LinkedIn profile URL."}},"required":["name"]}},"booking_url":{"type":"string","description":"Book-a-call URL (Cal.com, Calendly, ...)."},"contact_email":{"type":"string","description":"Public contact email."},"services":{"type":"array","description":"Services offered (multi-select from the curated set).","items":{"type":"string","enum":["Cold Email","LinkedIn Outbound","Lead Sourcing & Enrichment","GTM Engineering","Outreach Strategy & Consulting","Copywriting & Messaging","Deliverability & Infrastructure","RevOps & CRM","Campaign Management","Training & Coaching","Education"]}},"regions":{"type":"array","description":"Regions served (multi-select from the curated set).","items":{"type":"string","enum":["North America","LATAM","UK & Ireland","DACH","Nordics","Europe","APAC","Middle East & Africa","Global"]}}},"additionalProperties":false}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_directory_update"]}},"/api/cli/domains":{"get":{"operationId":"getDomains","tags":["Domains"],"summary":"List Domains","description":"Saved domain health; no provider calls. authentication=true: compact daily public DNS; attention=true: issues, unverified, stale or failed. Coverage: non-disabled sending mailboxes (paused included). q narrows domains. Default lists zone/managed/registered inventory. Zone DNS is a separate provider-cache check; unmatched means no synced zone, not no daily coverage. Full evidence: oxygen_domains_dns cached=true.\n\nMCP: `oxygen_domains_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"attention","in":"query","required":false,"schema":{"type":"boolean","description":"Daily health needing attention; implies authentication=true."}},{"name":"authentication","in":"query","required":false,"schema":{"type":"boolean","description":"Saved daily health and counts; supports q/attention. No zone inventory."}},{"name":"dns","in":"query","required":false,"schema":{"type":"string","description":"Zone DNS only: ok, issues, not_checked, check_failed, check_incomplete, no_zone. Use attention=true for daily authentication health."}},{"name":"expiring","in":"query","required":false,"schema":{"type":"boolean","description":"Only non-deleted domains expiring within 60 days."}},{"name":"has_mailboxes","in":"query","required":false,"schema":{"type":"boolean","description":"true → only domains with sending mailboxes; false → only domains without."}},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"Include archived domains (hidden by default)."}},{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Substring filter on the domain name."}},{"name":"registrar","in":"query","required":false,"schema":{"type":"string","description":"Filter by registrar (e.g. cloudflare)."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by zone status (e.g. active, pending, moved, deleted)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_domains_list"]}},"/api/cli/domains/{domain}":{"get":{"operationId":"getDomainsDomain","tags":["Domains"],"summary":"Get Domain Detail","description":"Domain detail and advisory readiness (never gates sending). cloudflare: cached DNS, registrar/RDAP age provenance, renewal and per-mailbox warmup/transport/caps, 7d/30d volume, 7d bounces, 30d replies and auto-pause. managed: subscription/mailbox rollup plus live vendor registration, renewal, nameservers/delegation, catch-all, DMARC mailbox, records and authentication verdict; unreachable vendor yields null. external: free public DNS/RDAP, MX provider, DMARC policy, web root, registrar/age and mailbox rollup. DKIM is ok or unknown, never missing: selector misses prove no absence. dns.status=unverified means only DKIM is unknown.\n\nMCP: `oxygen_domains_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_domains_get"]}},"/api/cli/domains/{domain}/archive":{"post":{"operationId":"postDomainsDomainArchive","tags":["Domains"],"summary":"Archive Domain","description":"Archives (or unarchives) a cached domain — an Oxygen-side declutter flag only. Nothing changes at Cloudflare: the zone, its DNS, and mailbox governance are untouched, syncs never resurrect the flag, and archived=false fully reverses it. Archived domains leave the default oxygen_domains_list and return with include_archived=true.\n\nMCP: `oxygen_domains_archive`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"archived":{"type":"boolean","description":"false to unarchive (default true)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_archive"]}},"/api/cli/domains/{domain}/dns":{"get":{"operationId":"getDomainsDomainDns","tags":["Domains"],"summary":"Check Domain DNS Health","description":"Domain DNS, 0 credits. cached=true: saved evidence/eligibility via oxygen_capabilities_read; no external calls or observation writes. authentication=true: save one free public SPF/DKIM/DMARC/MX/NS check; never enables monitoring or paid services. Daily coverage: non-disabled sending mailboxes (paused included). Otherwise reads live provider records and may save a zone verdict. deep=true adds content checks. Unknown selectors leave DKIM unverified; records do not verify active signing/alignment. plan/apply only edit supported Cloudflare zones.\n\nMCP: `oxygen_domains_dns`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}},{"name":"authentication","in":"query","required":false,"schema":{"type":"boolean","description":"Free observation only; no DNS edits or monitoring enrollment."}},{"name":"cached","in":"query","required":false,"schema":{"type":"boolean","description":"Saved evidence/eligibility; no external calls or observation writes. Overrides live flags."}},{"name":"deep","in":"query","required":false,"schema":{"type":"boolean","description":"Add content-level checks (SPF lookup budget, DMARC enforcement, MX provider)."}},{"name":"provider","in":"query","required":false,"schema":{"type":"string","description":"With deep=true: report whether the live MX matches this mailbox provider (google or microsoft)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_domains_dns"]}},"/api/cli/domains/{domain}/dns/apply":{"post":{"operationId":"postDomainsDomainDnsApply","tags":["Domains"],"summary":"Apply Domain DNS (write records)","description":"Writes planned cold-email DNS records into your own Cloudflare zone. Oxygen-bought DNS editing is unavailable; keep nameservers and contact support. Without approved=true, returns the oxygen_domains_dns_plan preview. Approval requires a fresh plan_hash; zone drift fails with plan_mismatch (409) before writing. Pass the same provider or sending_domain, auto_dkim and dkim as the plan. Re-plan after partial failure before retrying. 0 Oxygen credits.\n\nMCP: `oxygen_domains_dns_apply`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required true to actually write records. Without it, returns a preview."},"auto_dkim":{"type":"boolean","description":"Must match the plan (default true)."},"dkim":{"type":"array","description":"Must match the plan.","items":{"type":"object","properties":{"type":{"type":"string"},"name":{"type":"string"},"content":{"type":"string"}},"required":["type","name","content"]}},"dmarc_policy":{"type":"string","description":"Must match the plan."},"dmarc_rua":{"type":"string","description":"Must match the plan."},"plan_hash":{"type":"string","description":"The plan_hash from a fresh oxygen_domains_dns_plan (required with approved=true)."},"provider":{"type":"string","description":"google or microsoft; must match the plan."},"sending_domain":{"type":"string","description":"Sending domain whose SES records to write; must match the plan."},"tracking_host":{"type":"string","description":"Must match the plan."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_dns_apply"]}},"/api/cli/domains/{domain}/dns/plan":{"post":{"operationId":"postDomainsDomainDnsPlan","tags":["Domains"],"summary":"Plan Domain DNS (preview)","description":"FREE cold-email DNS preview: SPF, provider MX, DMARC, DKIM and optional tracking, diffed against live records as create/update/keep/conflict plus plan_hash. Writes nothing; 0 credits. Own Cloudflare zones only. Oxygen-bought DNS editing is unavailable; keep nameservers and contact support. Pass provider=google|microsoft. Microsoft DKIM selector CNAMEs are auto-derived from the initial *.onmicrosoft.com domain when dkim[] is omitted; dkim_note explains missing prerequisites. Set auto_dkim=false to skip. Google DKIM needs operator-supplied dkim[]. Apply with oxygen_domains_dns_apply and the returned plan_hash.\n\nMCP: `oxygen_domains_dns_apply`, `oxygen_domains_dns_plan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{},"auto_dkim":{"type":"boolean","description":"Auto-derive microsoft DKIM selector CNAMEs when no dkim[] is supplied (default true). Set false to skip auto-derivation."},"dkim":{"type":"array","description":"Per-provider DKIM records to include (each { type: 'TXT'|'CNAME', name, content }). Omit for microsoft to auto-derive; required for google (operator-supplied value).","items":{"type":"object","properties":{"type":{"type":"string"},"name":{"type":"string"},"content":{"type":"string"}},"required":["type","name","content"]}},"dmarc_policy":{"type":"string","description":"DMARC policy: 'none' (default), 'quarantine', or 'reject'."},"dmarc_rua":{"type":"string","description":"Optional DMARC aggregate-report mailbox (rua=mailto:...)."},"plan_hash":{},"provider":{"type":"string","description":"Mailbox provider: 'google' or 'microsoft' (determines SPF/MX/DKIM)."},"sending_domain":{"type":"string","description":"Instead plan this oxygen_domains_sending domain's SES records; provider then unused."},"tracking_host":{"type":"string","description":"Optional open/click tracking CNAME host (only planned when tracking is configured)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_dns_apply","oxygen_domains_dns_plan"]}},"/api/cli/domains/{domain}/forwarding":{"get":{"operationId":"getDomainsDomainForwarding","tags":["Domains"],"summary":"Get Domain Forwarding","description":"Configured/observed redirects; saves root evidence. Zero credits. Masking/verification: web_presence.\n\nMCP: `oxygen_domains_forwarding_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_domains_forwarding_get"]},"post":{"operationId":"postDomainsDomainForwarding","tags":["Domains"],"summary":"Set Domain Forwarding","description":"Compatibility website redirect control; mail routing untouched. Without approved previews exact changes. Apply requires approved and the returned plan_id/plan_hash. Zero Oxygen credits. Self-forwarding and replacing mask/relay/captcha settings are refused; use web_presence tools for those modes. Supports recorded managed connections or supported Cloudflare zones.\n\nMCP: `oxygen_domains_forwarding_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"true applies the change. Omit for a preview."},"forwarding_url":{"type":"string","description":"Destination http(s) URL. Pass an empty string to REMOVE the forward."},"plan_hash":{"type":"string","description":"Exact preview hash."},"plan_id":{"type":"string","description":"Exact preview plan ID."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_forwarding_set"]}},"/api/cli/domains/{domain}/renewal":{"post":{"operationId":"postDomainsDomainRenewal","tags":["Domains"],"summary":"Domain Renewal","description":"Turns yearly renewal of a domain bought through Oxygen on or off. No charge; off lets it lapse at expiry.\n\nMCP: `oxygen_domains_renewal`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"auto_renew":{"type":"boolean"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_renewal"]}},"/api/cli/domains/{domain}/tags":{"post":{"operationId":"postDomainsDomainTags","tags":["Domains"],"summary":"Tag Domain","description":"Replaces a sending domain's workspace tags (Tags primitive; see oxygen_tags_list). Whole-set: pass the full list, [] clears. Survives domain syncs.\n\nMCP: `oxygen_domains_tag`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"The full workspace tag list to set ([] clears)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_tag"]}},"/api/cli/domains/{domain}/tracking":{"get":{"operationId":"getDomainsDomainTracking","tags":["Domains"],"summary":"Open/Click Tracking Domain Status","description":"Returns the open/click tracking status for a domain: whether a tracking CNAME is configured, the tracking host, its verification status (pending | verified | failed | not_configured), the CNAME target, and whether the tracking signing secret is configured on the deployment. Reads the tenant cache only — zero Cloudflare calls and 0 Oxygen credits.\n\nMCP: `oxygen_domains_tracking_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_domains_tracking_status"]},"post":{"operationId":"postDomainsDomainTracking","tags":["Domains"],"summary":"Set Up Open/Click Tracking Domain","description":"Provisions the open/click tracking CNAME for a domain on its Cloudflare zone (the cluster-A DNS writer): `<track-host> CNAME <tracking target>`, DNS-only. WITHOUT approved=true this returns a PREVIEW of the exact record and writes nothing. WITH approved=true it writes the CNAME (idempotent — an existing record is reused) and records a 'pending' tracking domain. Default track host is track.<domain>; pass host to override (must be a subdomain of the domain). GATES: tracking must be configured (else tracking_not_configured), and link/pixel injection stays DISABLED until the response reports tracking_secret_configured=true. 0 Oxygen credits.\n\nMCP: `oxygen_domains_tracking_setup`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required true to write the CNAME; otherwise a preview is returned."},"host":{"type":"string","description":"Optional tracking subdomain (default track.<domain>); must be a subdomain of the domain."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_tracking_setup"]}},"/api/cli/domains/add":{"post":{"operationId":"postDomainsAdd","tags":["Domains"],"summary":"Add Domain (create Cloudflare zone)","description":"BYOK CLOUDFLARE ONLY. Onboards a domain registered elsewhere by creating a zone in the customer's connected Cloudflare account, then returns the nameservers required for delegation. FREE — no domain purchase and 0 Oxygen credits. For a new managed domain + inbox bundle use oxygen_managed_inboxes_subscribe.\n\nMCP: `oxygen_domains_add`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"The apex domain to add (e.g. acme.com)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_add"]}},"/api/cli/domains/adopt":{"post":{"operationId":"postDomainsAdopt","tags":["Domains"],"summary":"Adopt Managed Domains (staff)","description":"STAFF-ONLY LEGACY RECOVERY. Imports domains that ALREADY EXIST in the shared Oxygen-managed Cloudflare account into a workspace's ownership registry, then mirrors them into the domain cache. FREE — no purchase. Do not use this to provision new managed infrastructure; new managed domain + inbox bundles belong to InboxKit. Idempotent: foreign-owned domains are skipped and already-owned domains are no-ops. WITHOUT approved=true it previews and writes nothing.\n\nMCP: `oxygen_domains_adopt`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"all":{"type":"boolean","description":"Adopt every zone discovered in the shared managed Cloudflare account."},"approved":{"type":"boolean","description":"Required true to execute; otherwise a preview is returned and nothing is written."},"domains":{"type":"array","items":{"type":"string"},"description":"Specific domains to adopt (e.g. send.acme.com). Omit and set all=true to adopt the whole managed account."},"organization_id":{"type":"string","description":"Staff override: target workspace id (defaults to the caller's workspace)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_adopt"]}},"/api/cli/domains/buy":{"post":{"operationId":"postDomainsBuy","tags":["Domains"],"summary":"Buy Domains","description":"Without approved=true, returns a free preview and quote_id; nothing is purchased. NON-REFUNDABLE. Null tier means unknown, not non-premium. Without own Cloudflare, bills credits at registrar cost for one year; the separate renewal estimate can be unknown, charged 30 days before expiry. Own Cloudflare bills its card for 0 credits. Purchase needs approved=true plus quote_id; premium also needs accept_premium_pricing.\n\nMCP: `oxygen_domains_buy`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"accept_premium_pricing":{"type":"boolean","description":"Required true when any domain is premium-tier."},"approved":{"type":"boolean","description":"Required true to actually purchase; otherwise a preview with a quote_id is returned."},"auto_renew":{"type":"boolean","description":"Renew yearly (default true)."},"billing":{"type":"object","description":"Registrant contact, needed once when none is on file.","additionalProperties":{"type":"string"}},"domains":{"type":"array","items":{"type":"string"}},"privacy":{"type":"boolean","description":"Enable WHOIS privacy (default true)."},"quote_id":{"type":"string","description":"The quote_id from the preview response. Required with approved=true."},"redirect_url":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_buy"]}},"/api/cli/domains/check":{"post":{"operationId":"postDomainsCheck","tags":["Domains"],"summary":"Check Domain Availability","description":"Check 1-20 exact names: first-year registration + separate renewal estimate (null=unknown). Null tier means unknown, not non-premium. Own Cloudflare bills USD; Oxygen bills credits. Free; reason=owned means yours. Preview with oxygen_domains_buy.\n\nMCP: `oxygen_domains_check`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"string"},"description":"Exact domains to check (1-20, e.g. getacme.com)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_check"]}},"/api/cli/domains/delete":{"post":{"operationId":"domains.delete","tags":["Domains"],"summary":"Domains delete","description":"Preview domain and inbox removal; execute with the exact plan hash and confirmation. Oxygen-bought domains stop renewing but stay registered until expiry; no refund.\n\nMCP: `oxygen_domains_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"string"}},"approved":{"type":"boolean"},"plan_hash":{"type":"string"},"confirmation":{"type":"string"}},"required":["domains"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_delete"]}},"/api/cli/domains/registrations":{"get":{"operationId":"getDomainsRegistrations","tags":["Domains"],"summary":"List Domain Registrations","description":"Lists the org's domain purchase ledger (newest first) from the tenant cache — every registration attempt with status, price snapshot, and failure_reason — plus count and open_count (non-terminal registrations still in flight). Optional status filter: submitting, in_progress, succeeded, failed, action_required, or blocked. 0 credits; poll one known domain to a terminal state with oxygen_domains_registration_status.\n\nMCP: `oxygen_domains_registrations_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by ledger status (submitting, in_progress, succeeded, failed, action_required, blocked)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_domains_registrations_list"]}},"/api/cli/domains/registrations/{domain}":{"get":{"operationId":"getDomainsRegistrationsDomain","tags":["Domains"],"summary":"Domain Registration Status","description":"Returns the purchase-ledger status for one domain registration (submitting, in_progress, succeeded, failed, action_required, or blocked, with failure_reason when failed). The server performs at most one gated Cloudflare poll per call when due, so it is safe to poll repeatedly until the registration is terminal; action_required resolves in the Cloudflare dashboard.\n\nMCP: `oxygen_domains_registration_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_domains_registration_status"]}},"/api/cli/domains/search":{"get":{"operationId":"getDomainsSearch","tags":["Domains"],"summary":"Search Purchasable Domains","description":"Searches purchasable domains for a query, with price. Free. With the customer's own Cloudflare account: its Registrar in USD (purchasable_via_api=false = dashboard only); otherwise credits per year at the registrar's cost.\n\nMCP: `oxygen_domains_search`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"q","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_domains_search"]}},"/api/cli/domains/sync":{"post":{"operationId":"postDomainsSync","tags":["Domains"],"summary":"Sync Domains from Cloudflare","description":"Refreshes Cloudflare-backed domains only (BYOK — read-only against Cloudflare, 0 Oxygen credits): zone pages, registrar metadata, RDAP age backfill, and DNS health checks. Vendor-managed bundle domains are explicitly counted as skipped and use live oxygen_domains_get / oxygen_domains_dns reads instead. Each call is bounded; when partial=true, call again to continue from next_page. Set full=true to restart at page 1.\n\nMCP: `oxygen_domains_sync`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"full":{"type":"boolean","description":"Restart a full sweep from the first zone page instead of continuing the cursor."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_domains_sync"]}},"/api/cli/domains/web-presence":{"get":{"operationId":"getDomainsWebPresence","tags":["Domains"],"summary":"Read Domain Website","description":"Read domain web presence. Zero credits. Pack: deliverability.\n\nMCP: `oxygen_domains_web_presence_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_domains_web_presence_get"]},"post":{"operationId":"postDomainsWebPresence","tags":["Domains"],"summary":"Configure Domain Website","description":"Public writes: approved + preview ID/hash. Reconcile uncertainty. Pack: deliverability.\n\nMCP: `oxygen_domains_web_presence_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["set","bulk","check","reconcile","defaults","destination_add","destination_check","destination_publish","destination_remove"],"description":"set/bulk: preview/apply; check: save health; reconcile: readback; defaults: policy; destination_*: proof/TXT."},"approved":{"type":"boolean"},"captcha_enabled":{"type":"boolean"},"destination_url":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"HTTPS site/owned neutral relay."},"domain":{"type":"string"},"domains":{"type":"array","items":{"type":"string"},"maxItems":100},"mode":{"type":"string","enum":["off","forward","mask","relay"],"description":"off: unmanaged; forward: 301; mask: InboxKit; relay: owned neutral; captcha disables mask."},"plan_hash":{"type":"string"},"plan_id":{"type":"string"},"relay_transport":{"type":"string","enum":["forward","mask"],"description":"Relay transport."},"root":{"type":"string","description":"Destination root."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_web_presence_set"]}},"/api/cli/egress":{"get":{"operationId":"getEgress","tags":["Egress"],"summary":"IP Inventory","description":"Lists the shared native worker IP and this workspace's dedicated IP history, with endpoint, tier, and status. Staff also see provider metadata. Routing is workspace-scoped. Read-only, 0 credits.\n\nMCP: `oxygen_egress_ips`, `oxygen_egress_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"assignment_offset","in":"query","required":false,"schema":{}},{"name":"view","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_egress_ips","oxygen_egress_status"]}},"/api/cli/egress/assign":{"post":{"operationId":"postEgressAssign","tags":["Egress"],"summary":"Assign Mailbox IPs","description":"Converges mailbox policy assignments: managed/shared by default, or the workspace's dedicated IP for every current and future inbox while its add-on is active. Shared egress_ip_id cannot override active dedicated egress. Pass mailboxes or all=true. Workspace scope remains the transport boundary. No spend, 0 credits. Admin/owner.\n\nMCP: `oxygen_egress_assign`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"all":{"type":"boolean","description":"Converge every current sending mailbox to managed/shared policy, or to the workspace's dedicated IP when that add-on is active."},"egressIpId":{},"egress_ip_id":{"type":"string","description":"Pin the targeted mailboxes to this egress IP id (must be active and org-visible)."},"mailboxes":{"type":"array","items":{"type":"string"},"description":"Mailbox ids or addresses to assign."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_egress_assign"]}},"/api/cli/egress/dedicated":{"get":{"operationId":"egress.dedicated.get","tags":["Egress"],"summary":"Egress dedicated status","description":"Read dedicated outbound egress status and its current monthly commitment without activating it.\n\nMCP: `oxygen_dedicated_egress_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_dedicated_egress_status"]},"post":{"operationId":"postEgressDedicated","tags":["Egress"],"summary":"Cancel Dedicated IP","description":"Cancels at the end of the paid 30-day period. Without approve=true, previews only. With approve=true, schedules retirement: dedicated routing continues until expiry, then returns to shared and billing stops. No refund or early cutoff. Admin/owner.\n\nMCP: `oxygen_egress_dedicated_cancel`, `oxygen_egress_dedicated_request`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approve":{"type":"boolean","description":"True schedules cancellation; omit for a no-side-effect preview."},"cancel":{},"confirm":{},"country":{},"location_country":{},"moveExisting":{},"move_existing":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_egress_dedicated_cancel","oxygen_egress_dedicated_request"]}},"/api/cli/egress/register":{"post":{"operationId":"postEgressRegister","tags":["Egress"],"summary":"Register IP","description":"STAFF-ONLY RECOVERY: registers ONE legacy/manual logical policy-inventory row in this deployment environment (dev API -> dev policy inventory, prod -> prod). It does not configure native send transport; native dedicated drains are created only by oxygen_egress_dedicated_request, and platform-reserved provider values are rejected. Secrets never pass through this tool: credential_ref names the Doppler env family EGRESS_CRED_<REF>_USERNAME/_PASSWORD. Non-staff get 403 staff_required.\n\nMCP: `oxygen_egress_register`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"credential_ref":{"type":"string","description":"Doppler credential-family name (A-Z, 0-9, _)."},"dedicated_organization_id":{"type":"string","description":"Organization id a dedicated-tier IP is reserved for."},"environment":{},"host":{"type":"string","description":"Proxy hostname or IP — bare, no scheme/port/credentials."},"ips":{},"port":{"type":"number","description":"Proxy port (1-65535)."},"protocol":{"type":"string","enum":["http","https","socks5"],"description":"Proxy protocol; defaults to http."},"session_label":{"type":"string","description":"Vendor session/order label for provenance."},"tier":{"type":"string","enum":["shared","dedicated"],"description":"shared (default) or dedicated (requires dedicated_organization_id)."},"vendor":{"type":"string","description":"Vendor slug for inventory provenance."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_egress_register"]}},"/api/cli/egress/rotate":{"post":{"operationId":"postEgressRotate","tags":["Egress"],"summary":"Mailbox IP Rotation (Retired)","description":"RETIRED compatibility tool: workspace-scoped egress cannot rotate one mailbox. Always fails closed with 409 egress_mailbox_rotation_unavailable; no provider call, charge, or state change. Use oxygen_egress_status or contact support. Mirrors `oxygen egress rotate --mailbox <id>`.\n\nMCP: `oxygen_egress_rotate`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approve":{"type":"boolean","description":"Retired compatibility flag; no rotation is executed."},"mailboxId":{},"mailbox_id":{"type":"string","description":"Mailbox id whose sending IP to rotate."},"vendor":{"type":"string","description":"Retired compatibility input; never used for a provider call."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_egress_rotate"]}},"/api/cli/email-assets":{"get":{"operationId":"getEmailAssets","tags":["Email assets"],"summary":"GET /api/cli/email-assets","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false},"post":{"operationId":"postEmailAssets","tags":["Email assets"],"summary":"POST /api/cli/email-assets","description":"Fields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"source_url":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true}},"/api/cli/email-documents":{"get":{"operationId":"getEmailDocuments","tags":["Email documents"],"summary":"Newsletters","description":"Newsletter email steps. content_get/content_set: the step's HTML (≤100 KB, revisioned; drafts only); merge tags are HTML-escaped; {{unsubscribe_url}} places the opt-out, else a footer is added. test_send: [Test] copy to ≤5 member emails (`to`; omit to list), 0.05 credits each, 20/day. templates (with starters); template_save (sequence+step_id, from_document_id, starter_id or html); template_rename/_delete (template_id). asset_upload hosts an image (source_url, or content_base64 ≤2 MB) and returns its URL; asset_list pages them. stats: deliveries, est. opens, link clicks, bounces, complaints, unsubscribes; recipients: statuses. Else 0 credits.\n\nMCP: `oxygen_newsletters`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_newsletters"]},"post":{"operationId":"postEmailDocuments","tags":["Email documents"],"summary":"Newsletters","description":"Newsletter email steps. content_get/content_set: the step's HTML (≤100 KB, revisioned; drafts only); merge tags are HTML-escaped; {{unsubscribe_url}} places the opt-out, else a footer is added. test_send: [Test] copy to ≤5 member emails (`to`; omit to list), 0.05 credits each, 20/day. templates (with starters); template_save (sequence+step_id, from_document_id, starter_id or html); template_rename/_delete (template_id). asset_upload hosts an image (source_url, or content_base64 ≤2 MB) and returns its URL; asset_list pages them. stats: deliveries, est. opens, link clicks, bounces, complaints, unsubscribes; recipients: statuses. Else 0 credits.\n\nMCP: `oxygen_newsletters`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"editor_json":{"type":"object","description":"Editor document."},"html":{"type":"string","description":"Email HTML."},"name":{"type":"string","description":"Document or template name."},"preview_text":{"type":"string","description":"Inbox preview line."},"role":{},"starter_id":{"type":"string","description":"simple-announcement, product-update or weekly-digest."},"text":{"type":"string","description":"Plain text; default from html."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_newsletters"]}},"/api/cli/email-documents/{documentId}":{"get":{"operationId":"getEmailDocumentsDocumentId","tags":["Email documents"],"summary":"Newsletters","description":"Newsletter email steps. content_get/content_set: the step's HTML (≤100 KB, revisioned; drafts only); merge tags are HTML-escaped; {{unsubscribe_url}} places the opt-out, else a footer is added. test_send: [Test] copy to ≤5 member emails (`to`; omit to list), 0.05 credits each, 20/day. templates (with starters); template_save (sequence+step_id, from_document_id, starter_id or html); template_rename/_delete (template_id). asset_upload hosts an image (source_url, or content_base64 ≤2 MB) and returns its URL; asset_list pages them. stats: deliveries, est. opens, link clicks, bounces, complaints, unsubscribes; recipients: statuses. Else 0 credits.\n\nMCP: `oxygen_newsletters`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}},{"name":"revision","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Revision to copy."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_newsletters"]},"post":{"operationId":"postEmailDocumentsDocumentId","tags":["Email documents"],"summary":"Newsletters","description":"Newsletter email steps. content_get/content_set: the step's HTML (≤100 KB, revisioned; drafts only); merge tags are HTML-escaped; {{unsubscribe_url}} places the opt-out, else a footer is added. test_send: [Test] copy to ≤5 member emails (`to`; omit to list), 0.05 credits each, 20/day. templates (with starters); template_save (sequence+step_id, from_document_id, starter_id or html); template_rename/_delete (template_id). asset_upload hosts an image (source_url, or content_base64 ≤2 MB) and returns its URL; asset_list pages them. stats: deliveries, est. opens, link clicks, bounces, complaints, unsubscribes; recipients: statuses. Else 0 credits.\n\nMCP: `oxygen_newsletters`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["content_get","content_set","templates","test_send","template_save","template_rename","template_delete","asset_upload","asset_list","stats","recipients"]},"name":{"type":"string","description":"Document or template name."},"revision":{"type":"integer","minimum":1,"description":"Revision to copy."},"role":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_newsletters"]},"patch":{"operationId":"patchEmailDocumentsDocumentId","tags":["Email documents"],"summary":"Newsletters","description":"Newsletter email steps. content_get/content_set: the step's HTML (≤100 KB, revisioned; drafts only); merge tags are HTML-escaped; {{unsubscribe_url}} places the opt-out, else a footer is added. test_send: [Test] copy to ≤5 member emails (`to`; omit to list), 0.05 credits each, 20/day. templates (with starters); template_save (sequence+step_id, from_document_id, starter_id or html); template_rename/_delete (template_id). asset_upload hosts an image (source_url, or content_base64 ≤2 MB) and returns its URL; asset_list pages them. stats: deliveries, est. opens, link clicks, bounces, complaints, unsubscribes; recipients: statuses. Else 0 credits.\n\nMCP: `oxygen_newsletters`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"editor_json":{"type":"object","description":"Editor document."},"expected_revision":{"type":"integer","minimum":1,"description":"Refuse if the document moved on."},"html":{"type":"string","description":"Email HTML."},"name":{"type":"string","description":"Document or template name."},"preview_text":{"type":"string","description":"Inbox preview line."},"text":{"type":"string","description":"Plain text; default from html."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_newsletters"]},"delete":{"operationId":"deleteEmailDocumentsDocumentId","tags":["Email documents"],"summary":"DELETE /api/cli/email-documents/{documentId}","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true}},"/api/cli/email/send":{"post":{"operationId":"postEmailSend","tags":["Email"],"summary":"Send One Email (Ad-hoc)","description":"Previews or sends ONE ad-hoc email without a Sequence. Supports optional native-send HTML, From name, Cc/Bcc, and exact or LRU mailbox selection. Zapbox uses Zapmail; OAuth/delegation mailboxes send natively. approved=true sends; omit it for the exact mailbox/transport preview. BYOK, 0 credits; sent mail lands in Unibox.\n\nMCP: `oxygen_email_send`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Send; omit for preview."},"bcc":{"type":"array","items":{"type":"string"},"description":"Blind recipients."},"body":{"type":"string","description":"Plain text."},"cc":{"type":"array","items":{"type":"string"},"description":"Visible recipients."},"display_name":{"type":"string","description":"From-name override."},"from":{"type":"string","description":"Mailbox id/address; omit for LRU."},"html":{"type":"string","description":"Optional native-send HTML."},"subject":{"type":"string","description":"Subject."},"to":{"type":"string","description":"One recipient."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_email_send"]}},"/api/cli/enrich-column/preview":{"post":{"operationId":"postEnrichColumnPreview","tags":["Enrich column"],"summary":"Preview Column Enrichment","description":"Preflights an enrichment intent without provider calls or credits. Supports mobile_phone, work_email, and linkedin_url (find a person's LinkedIn profile URL from name+company or email, with identity validation against the source name to reject common-name false positives). Work-email and mobile_phone previews return the auto-selected waterfall profile, provider preflight, and (phone) expected_match_rate. expected_credits / expected_credits_per_row model spend from the stated hit-rate and billing assumptions. estimated_credits / estimated_credits_per_row are the maximum executable source and verification costs, including escalation and pattern checks. A paid candidate may fail quality checks before another lane bills; attempt fees also add. Quote this maximum as 'up to'. Use recommended_max_credits as the suggested run ceiling; it combines expected spend with a variance band and headroom. expected_hit_rate is the modelled share of rows resolved, capped to measured coverage; expected_credits_hit_rates_assumed is true while those rates are assumptions, so say so when quoting. Both expected_* are null when a managed lane has no resolvable price. A lane on the customer's own key (BYOK) pays OXYGEN's platform fee on every call, hit or miss; provider_cost_breakdown[].byok_platform_fee_credits_per_call shows it and every estimate includes it. mobile_phone is input-aware and cost-ordered (cheapest provider that has the number wins, since phone is bill-on-hit); set verify_phone to also capture phone_line_type + phone_carrier. Use this before paid bulk enrichment; when credit_posture is sufficient, run with recommended_max_credits as the ceiling and do not ask the user solely to save credits.\n\nMCP: `oxygen_enrich_column_preview`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_premium_lanes":{"type":"boolean","description":"Opt in to managed lanes over 50 credits/call, off by default so an unattended run cannot bill-shock. Only linkedin_url has one (LeadMagic email_to_profile, 122.5cr)."},"capability":{"type":"string","description":"Enrichment capability: mobile_phone, work_email (set include_personal_email for the non-work mailbox too; personal_email alone is kept for old callers), or linkedin_url (find a LinkedIn profile URL from name+company or email). Each runs an ordered provider waterfall and normalizes results across providers; identity validation gates LinkedIn URL hits against the source name+company to avoid common-name false positives. verify_email instead GRADES an existing email column: MillionVerifier, escalating catch-all domains to BounceBan, writing valid | invalid | catch_all.","enum":["mobile_phone","work_email","personal_email","linkedin_url","verify_email"]},"company_domain_column":{"type":"string","description":"Column key or id containing the company domain. Required for linkedin_url and work_email when matched with full_name (or first/last name) and not relying on email or LinkedIn URL identity. Preferred over company_name_column when both exist.","minLength":1,"maxLength":120},"company_linkedin_url_column":{"type":"string","description":"Column key or id containing the company's LinkedIn URL for company identity fallback.","minLength":1,"maxLength":120},"company_name_column":{"type":"string","description":"Column key or id containing the company name. Used for linkedin_url and work_email when no domain is available. Pair with full_name_column or first/last name columns.","minLength":1,"maxLength":120},"email_column":{"type":"string","description":"Column key or id containing a known work email. For work_email, used as an identity fallback. For linkedin_url, primary input for email-to-profile providers like LeadMagic.","minLength":1,"maxLength":120},"email_pattern_validation":{"type":"string","description":"Pattern validation mode for domain-based work-email waterfalls. leadmagic_valid_only tries common email patterns through LeadMagic validation before paid finder steps. disabled skips that pre-step.","enum":["leadmagic_valid_only","disabled"]},"email_waterfall_profile":{"type":"string","description":"Work-email waterfall profile: auto chooses from mapped inputs; name_domain uses name+domain finders with pattern validation first; linkedin_url prioritizes profile-URL providers, ordered for cost and coverage; first_last_domain optimizes for first/last + domain columns, ordered for cost and coverage.","enum":["auto","name_domain","linkedin_url","first_last_domain"]},"filter":{"type":"object","description":"Row filter, e.g. {column:'mobile_phone_e164', op:'is_null'}.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"filters":{"type":"array","description":"Convenience ANDed filters. Normalized by the API to selection={mode:'filter', filters}.","items":{"type":"object","description":"Row filter, e.g. {column:'mobile_phone_e164', op:'is_null'}.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"minItems":1,"maxItems":20},"first_name_column":{"type":"string","description":"Column key or id containing the person's first name. Used by work_email and linkedin_url when full_name_column is not available.","minLength":1,"maxLength":120},"full_name_column":{"type":"string","description":"Column key or id containing the person's full name. Required for linkedin_url when email_column is not mapped. Used by Prospeo, LeadMagic, Hunter, Dropleads, ContactOut, BetterContact, and People Data Labs for work_email when no LinkedIn URL is mapped.","minLength":1,"maxLength":120},"include_personal_email":{"type":"boolean","description":"work_email only: also find the personal (non-work) email from the person's LinkedIn URL (column found automatically, or linkedin_url_column), billed on a hit; priced in the preview, written to the cell's personal_email."},"last_name_column":{"type":"string","description":"Column key or id containing the person's last name. Used by work_email and linkedin_url when full_name_column is not available.","minLength":1,"maxLength":120},"limit":{"type":"integer","description":"Compatibility shortcut for selection={mode:'limit', limit:N}. Preview defaults to 10 when no selection is passed.","minimum":1,"maximum":500000},"linkedin_url_column":{"type":"string","description":"Column key or id containing the person's LinkedIn profile URL. Required by BlitzAPI, and enough by itself for Prospeo, Hunter, ContactOut, BetterContact, People Data Labs, or Crustdata on your own key. Sales Navigator URLs are stripped before provider calls; map name+domain too when the column may contain /sales/lead URLs. Ignored for linkedin_url enrichment.","minLength":1,"maxLength":120},"on_existing_manual_column":{"type":"string","description":"How to handle a requested target column that already exists as a manual/source column.","enum":["error","write_if_empty","create_enrichment_column"]},"only_missing":{"type":"boolean","description":"If true and no explicit selection is provided, run only rows missing the capability's normalized output."},"phone_verification_credential_mode":{"type":"string","description":"ClearoutPhone credential mode for phone verification. Defaults to managed, with BYOK fallback when available.","enum":["managed","user_api_key"]},"phone_waterfall_profile":{"type":"string","description":"mobile_phone waterfall profile. auto picks per row from mapped inputs: usable (non-Sales-Nav) LinkedIn URL -> linkedin_url, else known email -> email, else name+company -> name_domain. Profiles are cost-ordered; phone is bill-on-hit, so the cheapest provider holding the number sets the price. Expected match ~30-60%. Omit unless forcing a profile.","enum":["auto","linkedin_url","email","name_domain"]},"provider_order":{"type":"array","description":"Optional source-provider preference order. Overrides the default waterfall profile. For work_email, the default profiles are already ordered for cost and coverage across whichever providers fit the mapped inputs. Use verify_phone to validate phone results with ClearoutPhone after a source provider returns a candidate.","items":{"type":"string","maxLength":80},"maxItems":10},"selection":{"type":"object","description":"Rows to preview or queue. Use mode='all', mode='limit' with limit, mode='row_ids' with row_ids, or mode='filter' with filters. For retry gaps, use mode='filter' with filters=[{column:'mobile_phone_e164', op:'is_null'}]. To retry incomplete provider chains, filter phone_enrichment_status eq incomplete_provider_error.","properties":{"mode":{"type":"string","enum":["all","limit","row_ids","filter"]},"limit":{"type":"integer","minimum":1,"maximum":500000},"row_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500000},"filters":{"type":"array","items":{"type":"object","description":"Row filter, e.g. {column:'mobile_phone_e164', op:'is_null'}.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"minItems":1,"maxItems":20}},"required":["mode"]},"source_column":{"type":"string","description":"Column key or id. For mobile_phone this is the LinkedIn profile URL column; for work_email prefer linkedin_url_column. Ignored for linkedin_url (it is the output).","minLength":1,"maxLength":120},"table":{"type":"string","description":"Workspace table id or slug.","minLength":1,"maxLength":200},"target_column":{"type":"string","description":"Target enrichment column key. Defaults to the capability payload column.","maxLength":120},"verify_phone":{"type":"boolean","description":"If true for mobile_phone enrichment, validate each found phone with ClearoutPhone. Refines confidence and writes phone_line_type (mobile/landline/voip) + phone_carrier companions — filter phone_line_type=mobile before dialer/SMS. A blocked verifier keeps the number as unverified rather than dropping it."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_enrich_column_preview"]}},"/api/cli/enrich-column/run":{"post":{"operationId":"postEnrichColumnRun","tags":["Enrich column"],"summary":"Run Column Enrichment","description":"Creates or reuses an enrichment column and queues a paid background table run. Supports mobile_phone, work_email and linkedin_url waterfalls. mobile_phone runs an input-aware cost-ordered profile (linkedin_url / email / name_domain via auto): the cheapest provider holding the number wins, since phone is bill-on-hit. verify_phone validates with ClearoutPhone and adds phone_line_type (mobile/landline/voip) + phone_carrier columns. work_email runs the selected cost-aware profile across whichever providers fit the mapped inputs. linkedin_url gates each hit through identity validation (name match + company evidence) and writes a normalized https://www.linkedin.com/in/<slug> URL with verified/guessed/unverified confidence. max_credits is a safety ceiling; unused credits are not spent. LIVE run: requires approved=true (after the user has seen the preview cost), else approval_required. If preview returned credit_posture=sufficient, use recommended_max_credits.\n\nMCP: `oxygen_enrich_column_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"allow_premium_lanes":{"type":"boolean","description":"Opt in to managed lanes over 50 credits/call, off by default so an unattended run cannot bill-shock. Only linkedin_url has one (LeadMagic email_to_profile, 122.5cr)."},"approved":{"type":"boolean","description":"Required for execution: pass true only after the user approved the previewed cost (oxygen_enrich_column_preview is free). Without it the run fails with approval_required — this call queues a LIVE background run that spends up to max_credits once a worker picks it up."},"capability":{"type":"string","description":"Enrichment capability: mobile_phone, work_email (set include_personal_email for the non-work mailbox too; personal_email alone is kept for old callers), or linkedin_url (find a LinkedIn profile URL from name+company or email). Each runs an ordered provider waterfall and normalizes results across providers; identity validation gates LinkedIn URL hits against the source name+company to avoid common-name false positives. verify_email instead GRADES an existing email column: MillionVerifier, escalating catch-all domains to BounceBan, writing valid | invalid | catch_all.","enum":["mobile_phone","work_email","personal_email","linkedin_url","verify_email"]},"company_domain_column":{"type":"string","description":"Column key or id containing the company domain. Required for linkedin_url and work_email when matched with full_name (or first/last name) and not relying on email or LinkedIn URL identity. Preferred over company_name_column when both exist.","minLength":1,"maxLength":120},"company_linkedin_url_column":{"type":"string","description":"Column key or id containing the company's LinkedIn URL for company identity fallback.","minLength":1,"maxLength":120},"company_name_column":{"type":"string","description":"Column key or id containing the company name. Used for linkedin_url and work_email when no domain is available. Pair with full_name_column or first/last name columns.","minLength":1,"maxLength":120},"email_column":{"type":"string","description":"Column key or id containing a known work email. For work_email, used as an identity fallback. For linkedin_url, primary input for email-to-profile providers like LeadMagic.","minLength":1,"maxLength":120},"email_pattern_validation":{"type":"string","description":"Pattern validation mode for domain-based work-email waterfalls. leadmagic_valid_only tries common email patterns through LeadMagic validation before paid finder steps. disabled skips that pre-step.","enum":["leadmagic_valid_only","disabled"]},"email_waterfall_profile":{"type":"string","description":"Work-email waterfall profile: auto chooses from mapped inputs; name_domain uses name+domain finders with pattern validation first; linkedin_url prioritizes profile-URL providers, ordered for cost and coverage; first_last_domain optimizes for first/last + domain columns, ordered for cost and coverage.","enum":["auto","name_domain","linkedin_url","first_last_domain"]},"filter":{"type":"object","description":"Row filter, e.g. {column:'mobile_phone_e164', op:'is_null'}.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"filters":{"type":"array","description":"Convenience ANDed filters. Normalized by the API to selection={mode:'filter', filters}.","items":{"type":"object","description":"Row filter, e.g. {column:'mobile_phone_e164', op:'is_null'}.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"minItems":1,"maxItems":20},"first_name_column":{"type":"string","description":"Column key or id containing the person's first name. Used by work_email and linkedin_url when full_name_column is not available.","minLength":1,"maxLength":120},"force":{"type":"boolean","description":"Re-run rows even when the target enrichment cell already has a value."},"full_name_column":{"type":"string","description":"Column key or id containing the person's full name. Required for linkedin_url when email_column is not mapped. Used by Prospeo, LeadMagic, Hunter, Dropleads, ContactOut, BetterContact, and People Data Labs for work_email when no LinkedIn URL is mapped.","minLength":1,"maxLength":120},"include_personal_email":{"type":"boolean","description":"work_email only: also find the personal (non-work) email from the person's LinkedIn URL (column found automatically, or linkedin_url_column), billed on a hit; priced in the preview, written to the cell's personal_email."},"last_name_column":{"type":"string","description":"Column key or id containing the person's last name. Used by work_email and linkedin_url when full_name_column is not available.","minLength":1,"maxLength":120},"limit":{"type":"integer","description":"Compatibility shortcut for selection={mode:'limit', limit:N}. Preview defaults to 10 when no selection is passed.","minimum":1,"maximum":500000},"linkedin_url_column":{"type":"string","description":"Column key or id containing the person's LinkedIn profile URL. Required by BlitzAPI, and enough by itself for Prospeo, Hunter, ContactOut, BetterContact, People Data Labs, or Crustdata on your own key. Sales Navigator URLs are stripped before provider calls; map name+domain too when the column may contain /sales/lead URLs. Ignored for linkedin_url enrichment.","minLength":1,"maxLength":120},"max_concurrency":{"type":"integer","description":"Maximum concurrent row items for this enrichment run. Defaults to 20.","minimum":1},"max_credits":{"type":"number","description":"Required safety ceiling for the queued enrichment run. Unused credits are not spent.","exclusiveMinimum":0},"on_existing_manual_column":{"type":"string","description":"How to handle a requested target column that already exists as a manual/source column.","enum":["error","write_if_empty","create_enrichment_column"]},"only_missing":{"type":"boolean","description":"If true and no explicit selection is provided, run only rows missing the capability's normalized output."},"phone_verification_credential_mode":{"type":"string","description":"ClearoutPhone credential mode for phone verification. Defaults to managed, with BYOK fallback when available.","enum":["managed","user_api_key"]},"phone_waterfall_profile":{"type":"string","description":"mobile_phone waterfall profile. auto picks per row from mapped inputs: usable (non-Sales-Nav) LinkedIn URL -> linkedin_url, else known email -> email, else name+company -> name_domain. Profiles are cost-ordered; phone is bill-on-hit, so the cheapest provider holding the number sets the price. Expected match ~30-60%. Omit unless forcing a profile.","enum":["auto","linkedin_url","email","name_domain"]},"provider_order":{"type":"array","description":"Optional source-provider preference order. Overrides the default waterfall profile. For work_email, the default profiles are already ordered for cost and coverage across whichever providers fit the mapped inputs. Use verify_phone to validate phone results with ClearoutPhone after a source provider returns a candidate.","items":{"type":"string","maxLength":80},"maxItems":10},"selection":{"type":"object","description":"Rows to preview or queue. Use mode='all', mode='limit' with limit, mode='row_ids' with row_ids, or mode='filter' with filters. For retry gaps, use mode='filter' with filters=[{column:'mobile_phone_e164', op:'is_null'}]. To retry incomplete provider chains, filter phone_enrichment_status eq incomplete_provider_error.","properties":{"mode":{"type":"string","enum":["all","limit","row_ids","filter"]},"limit":{"type":"integer","minimum":1,"maximum":500000},"row_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500000},"filters":{"type":"array","items":{"type":"object","description":"Row filter, e.g. {column:'mobile_phone_e164', op:'is_null'}.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"minItems":1,"maxItems":20}},"required":["mode"]},"source_column":{"type":"string","description":"Column key or id. For mobile_phone this is the LinkedIn profile URL column; for work_email prefer linkedin_url_column. Ignored for linkedin_url (it is the output).","minLength":1,"maxLength":120},"table":{"type":"string","description":"Workspace table id or slug.","minLength":1,"maxLength":200},"target_column":{"type":"string","description":"Target enrichment column key. Defaults to the capability payload column.","maxLength":120},"verify_phone":{"type":"boolean","description":"If true for mobile_phone enrichment, validate each found phone with ClearoutPhone. Refines confidence and writes phone_line_type (mobile/landline/voip) + phone_carrier companions — filter phone_line_type=mobile before dialer/SMS. A blocked verifier keeps the number as unverified rather than dropping it."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_enrich_column_run"]}},"/api/cli/enrichment/apply-default-cascade":{"post":{"operationId":"postEnrichmentApplyDefaultCascade","tags":["Enrichment"],"summary":"Apply Default Enrichment Cascade","description":"Patches an existing enrichment column to the server-side default provider cascade for its stored intent. Use dry_run=true first to inspect the normalized would-be definition without writing.\n\nMCP: `oxygen_enrichment_apply_default_cascade`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string","description":"Enrichment column id or key.","minLength":1,"maxLength":200},"dryRun":{},"dry_run":{"type":"boolean","description":"Return the normalized would-be merged definition without writing."},"table":{"type":"string","description":"Workspace table id or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_enrichment_apply_default_cascade"]}},"/api/cli/enrichment/catalog":{"get":{"operationId":"getEnrichmentCatalog","tags":["Enrichment"],"summary":"Enrichment Column Catalog","description":"Name the data, not the provider: `intents` lists every data type a table can fill (profile, email, phone, headcount, funding, tech stack, hiring, news, decision makers, signals) with status, inputs, fields, region bands (claims until measured), provider order as metadata, credits per row and the add call; `entries` keeps presets/capabilities/recipes. Read before oxygen_columns_add; 0 credits.\n\nMCP: `oxygen_enrichment_catalog`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_enrichment_catalog"]}},"/api/cli/feedback":{"post":{"operationId":"postFeedback","tags":["Feedback"],"summary":"Send Feedback","description":"Native workspace chat on enabled dev; Plain elsewhere, including production. Show the exact message and selected attachment and obtain customer confirmation before calling. Optional transcript_text or customer-selected gzip; off by default.\n\nMCP: `oxygen_feedback`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{},"category":{"type":"string","maxLength":80,"description":"Defaults to \"feedback\"."},"context":{"type":"object","description":"Relevant diagnostic context.","properties":{"operation":{"type":"string","description":"Failed operation."},"error_code":{"type":"string","description":"Error envelope code."},"run_ids":{"type":"array","items":{"type":"string"},"maxItems":20},"table_ids":{"type":"array","items":{"type":"string"},"maxItems":20},"deep_links":{"type":"array","items":{"type":"string"},"maxItems":20,"description":"Affected OXYGEN run/Table URLs."},"cli_version":{"type":"string"},"slack_permalink":{"type":"string","maxLength":500,"description":"Selected Slack message permalink."},"slack_channel_id":{"type":"string","maxLength":64,"description":"e.g. C0123ABC456 — where a forwarded report came from."},"customer_workspace":{"type":"string","maxLength":200,"description":"Reported workspace name or slug."},"environment":{"type":"object","properties":{"os":{"type":"string","maxLength":500},"node":{"type":"string","maxLength":500},"cli_version":{"type":"string","maxLength":500},"cwd":{"type":"string","maxLength":500},"shell":{"type":"string","maxLength":500},"terminal":{"type":"string","maxLength":500}},"additionalProperties":false}},"additionalProperties":false},"message":{"type":"string","minLength":1,"maxLength":20000,"description":"Customer feedback or bug report."},"severity":{"type":"string","enum":["low","normal","high"],"description":"Defaults to normal."},"text":{},"transcript":{"type":"object","description":"Customer-selected gzip/base64 transcript, instead of transcript_text.","properties":{"content_b64":{"type":"string","minLength":1,"maxLength":4000000},"source":{"type":"string","enum":["claude_code","codex","cursor","file","unknown"]},"session_id":{"type":"string"},"tool":{"type":"string"},"event_count":{"type":"number","minimum":0},"byte_size":{"type":"number","minimum":0},"format":{"type":"string","enum":["jsonl.gz.b64"]},"truncated":{"type":"boolean"}},"required":["content_b64"],"additionalProperties":false},"transcript_text":{"type":"string","maxLength":200000,"description":"Optional customer-approved conversation excerpt. Send only selected relevant text; the API redacts common credential shapes."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_feedback"]}},"/api/cli/find/run":{"post":{"operationId":"postFindRun","tags":["Find"],"summary":"Find Work Email","description":"Find work email via a provider waterfall. Prefer linkedin_url, or full_name + company_domain. Returns found, result.value, confidence (verified/catch_all/guessed/unverified), provider, attempts, and retry_safe (nothing billed, no own key).\n\nMCP: `oxygen_find_company`, `oxygen_find_email`, `oxygen_find_linkedin`, `oxygen_find_person`, `oxygen_find_personal_email`, `oxygen_find_phone`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"capability":{},"check_technologies":{},"fields":{},"include_raw":{},"list_fields":{},"max_credits":{"type":"number","description":"Required for live; caps Oxygen credits, not own-key spend.","exclusiveMinimum":0},"mode":{"type":"string","enum":["dry_run","live"],"description":"dry_run (default) previews free; live bills and needs max_credits."},"verify":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_find_company","oxygen_find_email","oxygen_find_linkedin","oxygen_find_person","oxygen_find_personal_email","oxygen_find_phone"]}},"/api/cli/home/standup":{"get":{"operationId":"getHomeStandup","tags":["Home"],"summary":"Workspace Standup","description":"The workspace standup as one read: what happened since this reader last looked, every queue waiting on a person (unread and positive replies, failed enrollments, cold deals, mailboxes needing attention, message reviews, workflow and collaboration approvals, mentions) with counts and deep-links, and a year of daily activity with sample trace ids. Read-only, 0 credits. `degraded` names any leg whose read failed, so a zero is never mistaken for a fact. The window is per user and runs from their own last look at Home (web, or plain `oxygen home` in a terminal); this read never moves it, so repeated calls report the same window. The web Home dropped this recap as unactionable for a person; an agent that cannot glance at six surfaces needs exactly the model it dropped.\n\nMCP: `oxygen_home_standup`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"mark_seen","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_home_standup"]}},"/api/cli/inbox":{"get":{"operationId":"getInbox","tags":["Inbox"],"summary":"List Inbox Conversations","description":"Unibox merges email/LinkedIn/WhatsApp by default, newest first; channel picks one. Primary omits negative statuses; All: ordinary threads. Status/unread/unanswered/dates span channels. Fuzzy search: every non-warmup thread/body; segment/unanswered ignored. Email-only: campaign/provider/domain/mailbox facets; Others/Sent/Warmup/DMARC.\n\nMCP: `oxygen_inbox_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"LinkedIn sender/connection/Unipile account id."}},{"name":"account_id","in":"query","required":false,"schema":{}},{"name":"bucket","in":"query","required":false,"schema":{"type":"string","enum":["primary","others"],"description":"Legacy; use segment."}},{"name":"channel","in":"query","required":false,"schema":{"type":"string","enum":["all","linkedin","email","whatsapp"],"description":"all (default, merged stream), email, linkedin, or whatsapp."}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"channel=all: prior next_cursor."}},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"Include archived conversations."}},{"name":"include_counts","in":"query","required":false,"schema":{"type":"boolean","description":"channel=all: false skips facet counts."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"offset","in":"query","required":false,"schema":{}},{"name":"responses_only","in":"query","required":false,"schema":{"type":"boolean","description":"Email: only threads with a reply."}},{"name":"search","in":"query","required":false,"schema":{"type":"string","description":"Fuzzy over names, subjects, bodies."}},{"name":"segment","in":"query","required":false,"schema":{"type":"string","enum":["all","primary","others","sent","warmup","dmarc"],"description":"Default all. The folders past primary/all are email-only."}},{"name":"sender_account_id","in":"query","required":false,"schema":{"type":"string","description":"DM sender-account ids. Empty = all connected."}},{"name":"sender_profile_id","in":"query","required":false,"schema":{"type":"string","description":"Sender profile ids (people)."}},{"name":"unanswered","in":"query","required":false,"schema":{"type":"boolean","description":"Only threads you have not replied to."}},{"name":"unread","in":"query","required":false,"schema":{"type":"boolean","description":"Only conversations with unread messages."}},{"name":"unread_only","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_inbox_list"]}},"/api/cli/inbox/{conversationId}":{"get":{"operationId":"getInboxConversationId","tags":["Inbox"],"summary":"Get Inbox Conversation","description":"Get one inbox conversation with its full chronological message thread, sales-intent status and suggested reply. Use before drafting a reply. Resolves any channel by default; channel narrows it. LinkedIn/WhatsApp may refresh provider history in the local mirror, free and without sending. Use stored_only to skip refresh; sender_account_id scopes DM history.\n\nMCP: `oxygen_inbox_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}},{"name":"lineage","in":"query","required":false,"schema":{}},{"name":"mark_read","in":"query","required":false,"schema":{}},{"name":"message_limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"sync","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_inbox_get"]}},"/api/cli/inbox/{conversationId}/analyze":{"post":{"operationId":"postInboxConversationIdAnalyze","tags":["Inbox"],"summary":"Analyze an Inbox Conversation","description":"Runs the default analysis on one conversation now — email (default), LinkedIn, or WhatsApp: assigns the triage status and a drafted reply. Email results mirror into the 'Unibox Inbox' table; a manually-set status is never overwritten. The worker does this automatically on new inbound messages — use this to (re)analyze on demand. An already-classified email is a free no-op unless force:true (a paid re-spend). A small paid AI call (managed credits).\n\nMCP: `oxygen_inbox_analyze`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["email","linkedin","whatsapp"],"description":"email (default), linkedin, or whatsapp."},"force":{"type":"boolean","description":"Re-analyze even if the email was already classified (a paid re-classification; spends one managed credit). Without it, an already-analyzed email is a free no-op. DMs always re-analyze."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_analyze"]}},"/api/cli/inbox/{conversationId}/archive":{"post":{"operationId":"postInboxConversationIdArchive","tags":["Inbox"],"summary":"Archive an Inbox Conversation","description":"Archives a conversation (triages it out of the Unibox), or restores it with archived=false. Channel-aware: email (default), LinkedIn, or WhatsApp — all three carry an archived state. A state change, not an external write — no approval needed.\n\nMCP: `oxygen_inbox_archive`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"archived":{"type":"boolean","description":"true (default) archives; false restores."},"channel":{"type":"string","enum":["email","linkedin","whatsapp"],"description":"email (default), linkedin, or whatsapp."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_archive"]}},"/api/cli/inbox/{conversationId}/attachments/{fileId}/uploaded":{"post":{"operationId":"postInboxConversationIdAttachmentsFileIdUploaded","tags":["Inbox"],"summary":"Upload Email Reply Attachment","description":"Upload a PDF, DOCX, XLSX, PPTX, TXT, or CSV to one existing email conversation. Pass the returned file.id to oxygen_inbox_send attachment_ids. Uploading does not send a message; unused files expire after 24 hours. Up to 5 files and 10 MiB total per reply.\n\nMCP: `oxygen_inbox_attachment_upload`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}},{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_attachment_upload"]}},"/api/cli/inbox/{conversationId}/attachments/upload-url":{"post":{"operationId":"postInboxConversationIdAttachmentsUploadUrl","tags":["Inbox"],"summary":"Upload Email Reply Attachment","description":"Upload a PDF, DOCX, XLSX, PPTX, TXT, or CSV to one existing email conversation. Pass the returned file.id to oxygen_inbox_send attachment_ids. Uploading does not send a message; unused files expire after 24 hours. Up to 5 files and 10 MiB total per reply.\n\nMCP: `oxygen_inbox_attachment_upload`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"byte_length":{},"name":{"type":"string","description":"Filename including a supported extension."},"sha256":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_attachment_upload"]}},"/api/cli/inbox/{conversationId}/forget-whatsapp":{"post":{"operationId":"postInboxConversationIdForgetWhatsapp","tags":["Inbox"],"summary":"Forget Old WhatsApp Chat","description":"Preview or permanently erase one terminal old WhatsApp chat and its messages from OXYGEN only. Requires the original sender and latest-message cutoff. For a separate deletion from a connected WhatsApp account, find whatsapp.chats_delete with oxygen_tools_search, inspect oxygen_tools_run_dry, then use oxygen_tools_run_live and verify the provider result. This tool alone does not delete from WhatsApp. Costs 0 credits.\n\nMCP: `oxygen_inbox_forget_whatsapp_chat`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"True permanently removes the mirror; omitted/false previews."},"before":{"type":"string","description":"ISO timestamp; every message must predate it."},"sender_account_id":{"type":"string","description":"Original disconnected WhatsApp sender UUID."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_inbox_forget_whatsapp_chat"]}},"/api/cli/inbox/{conversationId}/messages/{messageId}/delete":{"post":{"operationId":"postInboxConversationIdMessagesMessageIdDelete","tags":["Inbox"],"summary":"Delete a Sent LinkedIn Message","description":"Delete your sent LinkedIn message for everyone within 60 minutes; irreversible. Show the default preview before approved=true. Only your LinkedIn messages are supported. Costs 0 credits.\n\nMCP: `oxygen_inbox_delete_message`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"True deletes this exact message irreversibly; omitted/false previews."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_inbox_delete_message"]}},"/api/cli/inbox/{conversationId}/read":{"post":{"operationId":"postInboxConversationIdRead","tags":["Inbox"],"summary":"Mark Inbox Conversation Read","description":"Marks visible messages in an inbox conversation read, retaining selected DM sender scope: LinkedIn by default, WhatsApp with channel=whatsapp, or the email inbox with channel=email.\n\nMCP: `oxygen_inbox_mark_read`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["linkedin","whatsapp","email"],"description":"linkedin (default), whatsapp, or email."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_mark_read"]}},"/api/cli/inbox/{conversationId}/send":{"post":{"operationId":"postInboxConversationIdSend","tags":["Inbox"],"summary":"Reply to a Conversation","description":"Replies into a conversation on its own channel, resolved from the conversation when channel is omitted: an email thread replies from its own mailbox (threaded), a LinkedIn thread sends a Unipile message, a WhatsApp thread gets a warm reply (warm-only). Shared LinkedIn threads require sender_account_id from the conversation’s senderAccountIds. For email files, first call oxygen_inbox_attachment_upload and pass its file.id in attachment_ids. This is a REAL external write: call once with approved=false (default) to preview, then again with approved=true to actually send. Never send without showing the user the preview first.\n\nMCP: `oxygen_inbox_send`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Set true to actually send. Omit/false returns a preview only."},"attachment_ids":{"type":"array","items":{"type":"string"},"description":"Email only: ready file ids returned by oxygen_inbox_attachment_upload, up to 5 and 10 MiB total."},"attachments":{},"channel":{"type":"string","enum":["linkedin","whatsapp","email"],"description":"Optional: email, linkedin, or whatsapp. Resolved from the conversation when omitted."},"draft_id":{"type":"string","description":"When approving an AI reply-agent draft (email or LinkedIn), its id — marks the draft sent on success. Use the channel that matches the draft."},"sender_account_id":{"type":"string","description":"LinkedIn participant sender UUID from senderAccountIds. Required for a shared thread."},"text":{"type":"string","description":"Reply text to send.","minLength":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_send"]}},"/api/cli/inbox/{conversationId}/status":{"post":{"operationId":"postInboxConversationIdStatus","tags":["Inbox"],"summary":"Set Inbox Conversation Status","description":"Sets the triage status on a conversation — email (default), LinkedIn, or WhatsApp (e.g. interested, neutral, not_now, not_interested, or a custom label key). A manual override that locks out AI re-classification. Statuses share one taxonomy across channels; use oxygen_inbox_labels_list to see valid keys.\n\nMCP: `oxygen_inbox_set_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["email","linkedin","whatsapp"],"description":"email (default), linkedin, or whatsapp."},"source":{"type":"string","enum":["manual","ai"],"description":"Classification provenance; manual locks out AI reclassification."},"status":{"type":"string","description":"A status label key (system or custom)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_set_status"]}},"/api/cli/inbox/{conversationId}/tags":{"post":{"operationId":"postInboxConversationIdTags","tags":["Inbox"],"summary":"Tag Inbox Conversation","description":"Adds/removes workspace tags on a conversation — email (default), LinkedIn, or WhatsApp (Tags primitive; see oxygen_tags_list). Delta semantics: add unions, remove subtracts, remove wins. Internal metadata — never sent to the counterpart.\n\nMCP: `oxygen_inbox_tags`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"add":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"Tags to add; preserve case and match case-insensitively."},"channel":{"type":"string","enum":["email","linkedin","whatsapp"],"description":"email (default), linkedin, or whatsapp."},"remove":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"Tags to remove, matched case-insensitively."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_tags"]}},"/api/cli/inbox/auto-tagger":{"get":{"operationId":"getInboxAutoTagger","tags":["Inbox"],"summary":"Get AI Inbox Tagger Config","description":"Shows the AI Inbox Tagger config: enabled state, tag allowlist, target channels. Null when never configured.\n\nMCP: `oxygen_inbox_auto_tagger_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_inbox_auto_tagger_get"]},"post":{"operationId":"postInboxAutoTagger","tags":["Inbox"],"summary":"Configure AI Inbox Tagger","description":"Configures the AI Inbox Tagger: enable/disable, replace the tag allowlist (max 50; [] pauses tagging), pick target channels. It auto-applies allowlist tags to new inbound conversations on the existing analysis call (zero extra cost), additive-only, never re-adding a tag a human removed. No approval queue — tags are internal metadata.\n\nMCP: `oxygen_inbox_auto_tagger_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"channels":{"type":"array","items":{"type":"string","enum":["email","linkedin","whatsapp"]},"description":"Channels to tag — a non-empty subset. Omit to keep the stored set (default all three)."},"enabled":{"type":"boolean","description":"Turn the agent on/off."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"The full tag allowlist to set (replaces the whole set; [] clears)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_auto_tagger_set"]}},"/api/cli/inbox/bulk":{"post":{"operationId":"postInboxBulk","tags":["Inbox"],"summary":"Bulk Update Inbox Conversations","description":"Applies one triage action — set_status, archive, or unarchive — across up to 100 hand-picked conversation ids (from oxygen_inbox_list). Two-step: approved=false (default) PREVIEWS matched/unmatched and would-change counts, mutating nothing; approved=true EXECUTES. channel scopes the ids (email default, linkedin, whatsapp) — run once per channel. A state change, not an external write; set_status writes a manual override that locks out AI re-classification.\n\nMCP: `oxygen_inbox_bulk`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["set_status","archive","unarchive"],"description":"set_status (needs status), archive, or unarchive."},"approved":{"type":"boolean","description":"false (default) previews the counts only. true applies the action."},"channel":{"type":"string","enum":["email","linkedin","whatsapp"],"description":"Inbox channel the ids belong to: email (default), linkedin, or whatsapp."},"conversationIds":{},"conversation_ids":{"type":"string","description":"Comma-separated conversation ids (the uuids oxygen_inbox_list returns). Max 100 per call."},"ids":{},"status":{"type":"string","description":"Required when action=set_status: the status label key to set (e.g. interested)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_bulk"]}},"/api/cli/inbox/drafts":{"get":{"operationId":"getInboxDrafts","tags":["Inbox"],"summary":"List AI Reply Drafts","description":"Lists the AI reply-agent review queue: queued + edited by default, across email + LinkedIn. Select channel/conversation, skip with offset. Optional summary gives complete draft references and live next_offset (queue changes may shift pages); exact draft_id + value retrieves long bodies/metadata losslessly. Send via oxygen_inbox_send (text, approved=true, draft_id, matching channel); edit/reject with the draft tools. Never sends here.\n\nMCP: `oxygen_inbox_drafts_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"channel","in":"query","required":false,"schema":{"type":"string","enum":["email","linkedin"],"description":"Filter to one channel (email | linkedin); omit for both."}},{"name":"conversation_id","in":"query","required":false,"schema":{"type":"string","description":"Local email or LinkedIn conversation UUID. Never a provider chat id."}},{"name":"draft_id","in":"query","required":false,"schema":{"type":"string","description":"Exact eligible agent draft UUID, with all other queue filters still applied. Use for stable value selection."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Skip this many matching drafts; default 0. Live queue changes may shift offsets."}},{"name":"sequence_id","in":"query","required":false,"schema":{"type":"string","description":"Filter to one campaign (sequence) id (email drafts only)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_inbox_drafts_list"]}},"/api/cli/inbox/drafts/{draftId}":{"patch":{"operationId":"patchInboxDraftsDraftId","tags":["Inbox"],"summary":"Edit an AI Reply Draft","description":"Edits an open AI reply-agent draft's body before approval. Does not send.\n\nMCP: `oxygen_inbox_draft_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{},"text":{"type":"string","description":"The new draft body.","minLength":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_draft_update"]}},"/api/cli/inbox/drafts/{draftId}/reject":{"post":{"operationId":"postInboxDraftsDraftIdReject","tags":["Inbox"],"summary":"Reject an AI Reply Draft","description":"Rejects an open AI reply-agent draft so it leaves the review queue. Does not send anything.\n\nMCP: `oxygen_inbox_draft_reject`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Optional reason."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_draft_reject"]}},"/api/cli/inbox/import":{"post":{"operationId":"inbox.import","tags":["Inbox"],"summary":"Inbox import","description":"Import your own Instantly or Smartlead cold-email history into Messages (record timelines, messages query; not the Unibox). Runs on your connection; each read has the own-key fee. Never stops sequences or changes DNC. Resumable; dry_run reads one page.\n\nCLI: `oxygen inbox import`.\n\nMCP: `oxygen_inbox_import`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","enum":["instantly","smartlead"]},"connection_id":{"type":"string"},"campaign_id":{"type":"string"},"since":{"type":"string","description":"ISO timestamp; older mail is skipped."},"import_id":{"type":"string","description":"Continue this import."},"max_pages":{"type":"integer","minimum":0,"maximum":10},"dry_run":{"type":"boolean"}},"required":["provider"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_inbox_import"],"x-oxygen-cli-command":"oxygen inbox import"}},"/api/cli/inbox/labels":{"get":{"operationId":"getInboxLabels","tags":["Inbox"],"summary":"List Inbox Status Labels","description":"Lists the org's inbox status labels (the Instantly-style system set plus any custom labels), each with its Primary/Others bucket and whether the AI may assign it.\n\nMCP: `oxygen_inbox_labels_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"Include archived custom labels."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_inbox_labels_list"]},"post":{"operationId":"postInboxLabels","tags":["Inbox"],"summary":"Create Inbox Status Label","description":"Creates a custom inbox status label (the '+ Create Label' action). The key is slugified from the name when omitted. Set ai_settable=true (with a clear description of when it applies) to let the AI reply classifier assign this label to conversations.\n\nMCP: `oxygen_inbox_label_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ai_settable":{"type":"boolean","description":"Whether the AI reply classifier may assign this label (default false)."},"bucket":{"type":"string","enum":["primary","others"],"description":"Primary (default) or Others."},"color":{"type":"string","description":"Hex color (e.g. #2a78d6)."},"description":{"type":"string","description":"What the label means / when it applies — used by the AI classifier prompt."},"icon":{"type":"string","description":"Icon name; empty clears."},"key":{"type":"string","description":"Stable custom status key; defaults to name slug."},"name":{"type":"string","description":"Display name.","minLength":1},"sort_order":{"type":"number","description":"Numeric position; 0 is valid."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_label_create"]}},"/api/cli/inbox/labels/{key}":{"patch":{"operationId":"patchInboxLabelsKey","tags":["Inbox"],"summary":"Update Inbox Status Label","description":"Updates a status label's name, color, bucket, description, or (custom labels only) ai_settable flag. A system label's ai_settable flag is immutable and cannot be changed.\n\nMCP: `oxygen_inbox_label_restore`, `oxygen_inbox_label_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ai_settable":{"type":"boolean","description":"Whether the AI classifier may assign this label (custom labels only; ignored for system labels)."},"archived":{},"bucket":{"type":"string","enum":["primary","others"],"description":"New bucket."},"color":{"type":"string","description":"New hex color."},"description":{"type":"string","description":"What the label means / when it applies — used by the AI classifier prompt."},"icon":{"type":"string","description":"Icon name; empty clears."},"key":{"type":"string","description":"The label key to update."},"name":{"type":"string","description":"New display name."},"sort_order":{"type":"number","description":"Numeric position; 0 is valid."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_label_restore","oxygen_inbox_label_update"]},"delete":{"operationId":"deleteInboxLabelsKey","tags":["Inbox"],"summary":"Archive Inbox Status Label","description":"Archives a custom status label. System labels and labels still applied to a conversation are rejected.\n\nMCP: `oxygen_inbox_label_archive`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_inbox_label_archive"]}},"/api/cli/inbox/read-all":{"post":{"operationId":"postInboxReadAll","tags":["Inbox"],"summary":"Mark All Inbox Conversations Read","description":"Marks EVERY conversation matching the filters read across email, LinkedIn, and WhatsApp, not just one page. The filters are oxygen_inbox_list's own, so the scope is exactly what that list returns (never archived ones). Two-step: approved=false (default) PREVIEWS the matching unread count per channel and mutates nothing; approved=true EXECUTES. Bounded per call — re-run while has_more is true. Idempotent. A state change, not an external write — spends no credits.\n\nMCP: `oxygen_inbox_mark_all_read`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"false (default) previews the per-channel unread count only. true marks them read."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_mark_all_read"]}},"/api/cli/inbox/reply-agent":{"get":{"operationId":"getInboxReplyAgent","tags":["Inbox"],"summary":"Get AI Reply Agent Config","description":"Gets the AI reply-agent config (persona, tone, target campaigns/statuses, enabled flag). The agent only ever drafts replies — it never sends.\n\nMCP: `oxygen_inbox_reply_agent_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_inbox_reply_agent_get"]},"post":{"operationId":"postInboxReplyAgent","tags":["Inbox"],"summary":"Configure AI Reply Agent","description":"Configures the AI reply agent (the draft-only 'AI Sales Agent'). Enable it, set persona/tone/instructions/signature, choose which channels it drafts for (email and/or LinkedIn), and target specific campaigns and/or statuses. It auto-drafts replies into the review queue; a human approves+sends. It can NEVER auto-send. LinkedIn drafts are short, informal, and signature-free; email drafts carry the signature. WhatsApp is not supported.\n\nMCP: `oxygen_inbox_reply_agent_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"channels":{},"enabled":{"type":"boolean","description":"Turn the agent on/off."},"instructions":{"type":"string","description":"Extra drafting instructions."},"max_drafts_per_day":{"type":"integer","minimum":0,"maximum":5000,"description":"Per-day draft cap (shared across channels)."},"persona":{"type":"string","description":"Who the agent is (e.g. 'a friendly SDR at Acme')."},"signature":{"type":"string","description":"Signature appended to email drafts (LinkedIn drafts never carry one)."},"target_channels":{"type":"string","description":"Comma-separated channels to draft for: a non-empty subset of email, linkedin (default: email)."},"target_sequence_ids":{"type":"string","description":"Comma-separated campaign ids to draft for (empty = all; email only)."},"target_statuses":{"type":"string","description":"Comma-separated statuses to draft for (empty = all draftable)."},"tone":{"type":"string","description":"Reply tone (e.g. 'concise and warm')."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_reply_agent_set"]}},"/api/cli/inbox/reply-oxygent/{action}":{"get":{"operationId":"getInboxReplyOxygentAction","tags":["Inbox"],"summary":"GET /api/cli/inbox/reply-oxygent/{action}","description":"Fields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"action","in":"path","required":true,"schema":{"type":"string"}},{"name":"agent_slug","in":"query","required":false,"schema":{}},{"name":"batch_id","in":"query","required":false,"schema":{}},{"name":"channel","in":"query","required":false,"schema":{}},{"name":"conversation_id","in":"query","required":false,"schema":{}},{"name":"item_id","in":"query","required":false,"schema":{}},{"name":"knowledge_slug","in":"query","required":false,"schema":{}},{"name":"view","in":"query","required":false,"schema":{}},{"name":"voice_slug","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false},"post":{"operationId":"postInboxReplyOxygentAction","tags":["Inbox"],"summary":"POST /api/cli/inbox/reply-oxygent/{action}","description":"Fields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"action","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"agent_slug":{},"approved":{},"batch_id":{},"batch_size":{},"body":{},"context_hash":{},"enabled":{},"exclude_item_ids":{},"knowledge_slugs":{},"linkedin_account_id":{},"mailbox_ids":{},"preview_hash":{},"reviewed_item_ids":{},"sequence_ids":{},"source_hash":{},"voice_slug":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true}},"/api/cli/inbox/rescan":{"post":{"operationId":"postInboxRescan","tags":["Inbox"],"summary":"Re-categorize Inbox Conversations","description":"Re-queues conversations for background re-classification (status + drafted reply). Two-step: confirm=false (default) PREVIEWS how many would re-queue (email_count / dm_count / total) and mutates nothing; confirm=true EXECUTES (free for opt-outs, a cheap managed model otherwise, credit-capped). channel: all (default), email, linkedin, or whatsapp. Manually-set statuses are never overwritten. Use after changing your label taxonomy or analysis prompt.\n\nMCP: `oxygen_inbox_rescan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["all","email","linkedin","whatsapp"],"description":"Scope: all (default — email + LinkedIn + WhatsApp), email, linkedin, or whatsapp."},"confirm":{"type":"boolean","description":"false (default) previews the counts only. true re-queues the conversations for re-classification."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_rescan"]}},"/api/cli/inbox/sync":{"post":{"operationId":"postInboxSync","tags":["Inbox"],"summary":"Sync Inbox","description":"Forces a backstop sync from Unipile for LinkedIn and WhatsApp sender accounts, pulling recent chats and messages into the unibox. Email is never synced here: mailboxes are polled automatically, so email replies reach oxygen_inbox_list on their own. By default it syncs the few least-recently-synced sender accounts (bounded to the request budget; the rest refresh via the background backstop). Pass account to force-refresh one sender now. Use if the DM inbox looks stale; real-time updates normally arrive via webhooks.\n\nMCP: `oxygen_inbox_sync`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender account to force-sync now (sender id, connection id, or Unipile account id). Omit to sync the least-recently-synced accounts."},"chat_limit":{"type":"integer","minimum":1,"description":"Maximum chats to sync per account. Defaults to 30."},"message_limit":{"type":"integer","minimum":1,"description":"Maximum messages to sync per chat. Defaults to 20."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_sync"]}},"/api/cli/inbox/views":{"get":{"operationId":"getInboxViews","tags":["Inbox"],"summary":"List Unibox Views","description":"Lists the team's saved Unibox views (named filter states: senders, channels, statuses), each with its filters as inbox list params and web_url. is_default marks the caller's own default, which the Unibox opens on.\n\nMCP: `oxygen_inbox_views_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_inbox_views_list"]},"post":{"operationId":"postInboxViews","tags":["Inbox"],"summary":"Create Unibox View","description":"Saves a named Unibox view for the whole team. filters is a Unibox URL or a query string of oxygen_inbox_list params (e.g. sender_profile_id=<id>&channels=linkedin&status=interested); without segment it opens on Primary, segment=all on every conversation. default=true also makes it the caller's own default.\n\nMCP: `oxygen_inbox_view_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"default":{"type":"boolean","description":"Also make it the caller's default view."},"filters":{"type":"string","description":"Unibox URL or inbox list query string."},"name":{"type":"string","description":"Unique in the workspace; up to 80 characters.","minLength":1,"maxLength":80}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_view_create"]}},"/api/cli/inbox/views/{viewId}":{"patch":{"operationId":"patchInboxViewsViewId","tags":["Inbox"],"summary":"Update Unibox View","description":"Renames, re-filters (replaces filters) or reorders a team Unibox view. default=true makes it the caller's own default; default=false stops using it as one.\n\nMCP: `oxygen_inbox_view_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"viewId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"default":{"type":"boolean","description":"true: caller's default; false: stop using it."},"filters":{"type":"string","description":"Replacement filters: Unibox URL or query string."},"name":{"type":"string","description":"New name.","minLength":1,"maxLength":80},"position":{"type":"integer","minimum":0,"description":"Zero-based order in the list."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_view_update"]},"delete":{"operationId":"deleteInboxViewsViewId","tags":["Inbox"],"summary":"Delete Unibox View","description":"Deletes a team Unibox view. Members who used it as their default open on the built-in view.\n\nMCP: `oxygen_inbox_view_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"viewId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_inbox_view_delete"]}},"/api/cli/inbox/whatsapp/start":{"post":{"operationId":"postInboxWhatsappStart","tags":["Inbox"],"summary":"Start WhatsApp Chat","description":"Preview or send the first message of a one-to-one WhatsApp chat from a connected sender. Use a phone with country code or a CRM person row id. A cold chat uses an unofficial linked-device connection and can increase account restriction risk. Preview first; approved=true sends a real message.\n\nMCP: `oxygen_inbox_start_whatsapp`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"True sends; false or omitted previews."},"person_row_id":{"type":"string","description":"CRM people row id; choose this or phone."},"phone":{"type":"string","description":"Recipient phone with country code; choose this or person_row_id."},"sender_account_id":{"type":"string","description":"Connected WhatsApp sender account id."},"text":{"type":"string","description":"First message."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_start_whatsapp"]}},"/api/cli/integrations/{integrationId}/test":{"post":{"operationId":"integrations.connection.test","tags":["Integrations"],"summary":"Integrations connection test","description":"Test one workspace integration connection and save its health without changing its default or returning credentials.\n\nCLI: `oxygen integrations connection-test`.\n\nMCP: `oxygen_integration_connection_test`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"integrationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_integration_connection_test"],"x-oxygen-cli-command":"oxygen integrations connection-test"}},"/api/cli/integrations/cloudflare/connect":{"post":{"operationId":"integrations.cloudflare","tags":["Integrations"],"summary":"Integrations cloudflare connect","description":"Verify a Cloudflare token, choose an account when required, and save the encrypted connection. account_id is optional for initial account discovery; no credential is returned.\n\nCLI: `oxygen integrations cloudflare-connect`.\n\nMCP: `oxygen_cloudflare_connect`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"api_key":{"type":"string"},"account_id":{"type":"string"}},"required":["api_key"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_cloudflare_connect"],"x-oxygen-cli-command":"oxygen integrations cloudflare-connect"}},"/api/cli/integrations/composio/actions":{"get":{"operationId":"getIntegrationsComposioActions","tags":["Integrations"],"summary":"List Integration Actions","description":"Lists the actions available for an integration — both Composio toolkits (e.g. all Slack actions) and native-provider integrations (Salesforge and the Forge family, Instantly, …, which expose their full API as actions, including campaign/sequence creation). Includes input/output schemas so you can call them.\n\nMCP: `oxygen_integrations_list_actions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"integrationId","in":"query","required":false,"schema":{}},{"name":"integration_id","in":"query","required":false,"schema":{"type":"string","description":"Integration id, such as 'slack'.","minLength":1,"maxLength":80}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_integrations_list_actions"]}},"/api/cli/integrations/composio/endpoints":{"get":{"operationId":"integrations.managed_endpoints","tags":["Integrations"],"summary":"Integrations managed endpoints","description":"Read a managed integration's full action catalog and parameter schemas.\n\nCLI: `oxygen integrations managed-endpoints`.\n\nMCP: `oxygen_integration_managed_endpoints`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"integration_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_integration_managed_endpoints"],"x-oxygen-cli-command":"oxygen integrations managed-endpoints"}},"/api/cli/integrations/composio/list":{"get":{"operationId":"getIntegrationsComposioList","tags":["Integrations"],"summary":"List Integrations","description":"Lists supported Composio-backed integrations plus this organization's stored integration connections (including native-provider connections like Salesforge and the Forge family), with reconnect-required BYOK health. Pass integration_id to read one.\n\nMCP: `oxygen_integrations_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_integrations_list"]}},"/api/cli/integrations/composio/run":{"post":{"operationId":"postIntegrationsComposioRun","tags":["Integrations"],"summary":"Run Integration Action","description":"Runs an action for a connected integration — a Composio action or a native-provider operation (Salesforge and the Forge family, Instantly, …). Defaults to dry-run. Live side effects require approved=true. After repricing, native and Composio actions on a workspace API key also cost 0.05 OXYGEN credits per provider call; inspect the dry-run quote and pass max_credits of at least that amount for mode='live'. Managed Composio actions require approved=true plus their quoted max_credits.\n\nMCP: `oxygen_integrations_run_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"actionSlug":{},"action_slug":{"type":"string","description":"Action slug. For Composio toolkits this is the action slug (e.g. 'SLACK_SEND_MESSAGE'); for native-provider integrations (Salesforge, the Forge family, Instantly, …) it is the operation name (e.g. 'get_workspaces', 'post_multichannel_workspaces_by_workspace_id_sequences'). Use the actions list tool to discover slugs.","minLength":1,"maxLength":200},"approved":{"type":"boolean","description":"Set true to acknowledge the dry-run preview and approve live execution. Required for live Composio actions, and for live side-effecting native-provider actions (external writes / paid provider calls)."},"arguments":{"type":"object","description":"Arguments JSON object passed to the action. Validate against the action's input_schema.","additionalProperties":true},"connectionId":{},"connection_id":{"type":"string","description":"Target a specific connected account when several exist for this native-provider integration. Omit to use the org's default connection.","minLength":1,"maxLength":200},"credentialMode":{},"credential_mode":{"type":"string","enum":["managed","user_api_key","user_oauth"]},"input":{},"integrationId":{},"integration_id":{"type":"string","description":"Integration id, such as 'slack'.","minLength":1,"maxLength":80},"max_credits":{"type":"number","description":"Positive credit cap for the live action. This is required with mode='live'; unused credits are not spent.","exclusiveMinimum":0},"mode":{"type":"string","description":"Execution mode. Defaults to 'dry_run' for safety.","enum":["dry_run","live"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_integrations_run_action"]}},"/api/cli/integrations/connect":{"post":{"operationId":"postIntegrationsConnect","tags":["Integrations"],"summary":"Connect Integration","description":"Connect a provider account, including X (integration_id=twitter). OAuth creates pending authorization; inspect prices first with oxygen_billing_commitments view=connection-prices. For API keys, omit credentials for a setup preview with no provider call or storage; relay required_scopes. Submitting api_key creates or replaces the connection immediately, without separate approval. BounceBan validates before storage. Use credentials.subdomain for PostHog; top-level account_id for Cloudflare account selection.\n\nMCP: `oxygen_integrations_connect`, `oxygen_supabase_connection_open`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","description":"Cloudflare account id from needs_account_selection. Omit for a single-account token."},"acknowledge_linkedin_risk":{},"api_key":{"type":"string","description":"Provider key/token shorthand. PostHog maps this to generic_api_key, never subdomain.","minLength":1,"maxLength":4000},"country":{},"database_url":{"type":"string","description":"Supabase managed read-only PostgreSQL URL; encrypted after validation."},"integration_id":{"type":"string","description":"Integration id, such as 'slack'.","minLength":1,"maxLength":80},"pairing_phone_number":{},"return_to":{"type":"string","description":"In-product destination after OAuth approval."},"schemas":{"type":"string","description":"Supabase comma-separated schemas; default public."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_integrations_connect","oxygen_supabase_connection_open"]}},"/api/cli/integrations/connections":{"get":{"operationId":"integrations.connections","tags":["Integrations"],"summary":"Integrations connections","description":"List this workspace's stored integration connections and health without credentials.\n\nCLI: `oxygen integrations connections`.\n\nMCP: `oxygen_integrations_connections`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"integration_id","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_integrations_connections"],"x-oxygen-cli-command":"oxygen integrations connections"}},"/api/cli/integrations/default":{"post":{"operationId":"integrations.default","tags":["Integrations"],"summary":"Integrations default","description":"Set the default active integration connection within this workspace.\n\nCLI: `oxygen integrations default`.\n\nMCP: `oxygen_integration_default_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"integration_id":{"type":"string"},"connection_id":{"type":"string"}},"required":["integration_id","connection_id"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_integration_default_set"],"x-oxygen-cli-command":"oxygen integrations default"}},"/api/cli/integrations/destinations":{"get":{"operationId":"getIntegrationsDestinations","tags":["Integrations"],"summary":"List Integration Destinations","description":"Lists where a connected integration can send, so you never ask a user to paste a raw provider id. For Microsoft Teams: the teams and chats they can reach, plus one team's channels when team_id is supplied. Use this to resolve the team_id + channel_id that MICROSOFT_TEAMS_TEAMS_POST_CHANNEL_MESSAGE needs, or the chat_id that MICROSOFT_TEAMS_TEAMS_POST_CHAT_MESSAGE needs (the Teams node in a workflow takes the same ids). These are read-only lookups: free, no approval and no credit cap. Note Microsoft lists every team in the tenant, not only joined ones, and a team the account has not joined answers Forbidden on its channels. Currently supported: microsoft_teams.\n\nMCP: `oxygen_integrations_list_destinations`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"connectionId","in":"query","required":false,"schema":{}},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","description":"Target a specific connected account when several exist for this native-provider integration. Omit to use the org's default connection.","minLength":1,"maxLength":200}},{"name":"integrationId","in":"query","required":false,"schema":{}},{"name":"integration_id","in":"query","required":false,"schema":{"type":"string","description":"Integration id, such as 'slack'.","minLength":1,"maxLength":80}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["teams","channels","chats"],"description":"Narrow to one destination shape and run exactly one provider lookup. 'channels' requires team_id. Omit to list teams and chats."}},{"name":"teamId","in":"query","required":false,"schema":{}},{"name":"team_id","in":"query","required":false,"schema":{"type":"string","description":"List this team's channels as well. Omit to list teams and chats only."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_integrations_list_destinations"]}},"/api/cli/integrations/disconnect":{"post":{"operationId":"postIntegrationsDisconnect","tags":["Integrations"],"summary":"Disconnect Integration","description":"Disconnects an integration by connection_id. Custom HTTP previews removal first; confirm with approved and its plan_hash. Other connectors disconnect immediately.\n\nMCP: `oxygen_integrations_disconnect`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Approve custom HTTP removal after reviewing its preview."},"connection_id":{"type":"string","description":"Disconnect a specific connected account when several exist for this integration. Omit to disconnect the org's default connection.","minLength":1,"maxLength":200},"integration_id":{"type":"string","description":"Integration id, such as 'slack'.","minLength":1,"maxLength":80},"plan_hash":{"type":"string","description":"Custom HTTP removal preview hash."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_integrations_disconnect"]}},"/api/cli/integrations/events":{"get":{"operationId":"getIntegrationsEvents","tags":["Integrations"],"summary":"List Integration Events","description":"Lists raw provider webhook definitions and this organization's enabled subscriptions. Use oxygen_workflows_events_list for the trigger-ready workspace catalog.\n\nMCP: `oxygen_integration_events_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"event","in":"query","required":false,"schema":{"type":"string","description":"Provider event type, such as 'contact.created' or 'GMAIL_NEW_GMAIL_MESSAGE'.","minLength":1,"maxLength":120}},{"name":"event_type","in":"query","required":false,"schema":{}},{"name":"integration_id","in":"query","required":false,"schema":{}},{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Provider event source, such as 'hubspot' or 'composio.gmail'.","minLength":1,"maxLength":80}},{"name":"toolkit","in":"query","required":false,"schema":{"type":"string","description":"Optional toolkit / integration id to filter the catalog, such as 'gmail'.","minLength":1,"maxLength":80}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_integration_events_list"]}},"/api/cli/integrations/events/deliveries":{"get":{"operationId":"getIntegrationsEventsDeliveries","tags":["Integrations"],"summary":"List Integration Event Deliveries","description":"Lists recent provider webhook deliveries (Composio triggers, HubSpot webhooks, etc.) for this organization, including the resulting workflow run ids. Use this to debug whether a provider's webhook reached Oxygen and which workflow run handled it.\n\nMCP: `oxygen_integration_events_deliveries`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"connectionId","in":"query","required":false,"schema":{}},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","description":"Optional integration connection id. Defaults to the active default connection.","minLength":1,"maxLength":120}},{"name":"event","in":"query","required":false,"schema":{"type":"string","description":"Provider event type, such as 'contact.created' or 'GMAIL_NEW_GMAIL_MESSAGE'.","minLength":1,"maxLength":120}},{"name":"event_type","in":"query","required":false,"schema":{}},{"name":"integration_id","in":"query","required":false,"schema":{}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Max deliveries to return (1-200). Defaults to 50.","minimum":1,"maximum":200}},{"name":"result","in":"query","required":false,"schema":{"type":"string","description":"Filter by delivery result. 'success' for dispatched deliveries, 'error' for failures.","enum":["success","error"]}},{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Provider event source, such as 'hubspot' or 'composio.gmail'.","minLength":1,"maxLength":80}},{"name":"toolkit","in":"query","required":false,"schema":{"type":"string","description":"Optional toolkit / integration id to filter the catalog, such as 'gmail'.","minLength":1,"maxLength":80}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_integration_events_deliveries"]}},"/api/cli/integrations/events/disable":{"post":{"operationId":"postIntegrationsEventsDisable","tags":["Integrations"],"summary":"Disable Integration Event","description":"Disables a provider event subscription so matching provider webhooks stop triggering workflows.\n\nMCP: `oxygen_integration_events_disable`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{},"connection_id":{"type":"string","description":"Optional integration connection id. Defaults to the active default connection.","minLength":1,"maxLength":120},"event":{"type":"string","description":"Provider event type, such as 'contact.created' or 'GMAIL_NEW_GMAIL_MESSAGE'.","minLength":1,"maxLength":120},"eventType":{},"event_type":{},"source":{"type":"string","description":"Provider event source, such as 'hubspot' or 'composio.gmail'.","minLength":1,"maxLength":80}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_integration_events_disable"]}},"/api/cli/integrations/events/enable":{"post":{"operationId":"postIntegrationsEventsEnable","tags":["Integrations"],"summary":"Enable Integration Event","description":"Enables a provider event subscription so matching provider webhooks can trigger workflows.\n\nMCP: `oxygen_integration_events_enable`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{},"connection_id":{"type":"string","description":"Optional integration connection id. Defaults to the active default connection.","minLength":1,"maxLength":120},"event":{"type":"string","description":"Provider event type, such as 'contact.created' or 'GMAIL_NEW_GMAIL_MESSAGE'.","minLength":1,"maxLength":120},"eventType":{},"event_type":{},"source":{"type":"string","description":"Provider event source, such as 'hubspot' or 'composio.gmail'.","minLength":1,"maxLength":80},"triggerConfig":{},"trigger_config":{"type":"object","description":"Provider-specific trigger configuration (Composio triggers only). See the catalog entry's providerSetup.configSchema.","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_integration_events_enable"]}},"/api/cli/integrations/github/branches":{"get":{"operationId":"getIntegrationsGithubBranches","tags":["Integrations"],"summary":"Knowledge Repository","description":"Manage GitHub Knowledge mounts after GitHub auth. Preview before connect; two_way permits branch writes. Conflict resolves pin the reviewed revision and SHA. 0 credits.\n\nMCP: `oxygen_knowledge_repository`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_repository"]}},"/api/cli/integrations/github/repositories":{"get":{"operationId":"getIntegrationsGithubRepositories","tags":["Integrations"],"summary":"Knowledge Repository","description":"Manage GitHub Knowledge mounts after GitHub auth. Preview before connect; two_way permits branch writes. Conflict resolves pin the reviewed revision and SHA. 0 credits.\n\nMCP: `oxygen_knowledge_repository`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_repository"]}},"/api/cli/integrations/github/start":{"post":{"operationId":"integrations.github.start","tags":["Integrations"],"summary":"Integrations github start","description":"Create the authenticated GitHub authorization URL for this workspace.\n\nCLI: `oxygen integrations github-start`.\n\nMCP: `oxygen_github_connection_start`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"return_to":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_github_connection_start"],"x-oxygen-cli-command":"oxygen integrations github-start"}},"/api/cli/integrations/hubspot/start":{"post":{"operationId":"integrations.hubspot.start","tags":["Integrations"],"summary":"Integrations hubspot start","description":"Create the authenticated HubSpot authorization URL for this workspace.\n\nCLI: `oxygen integrations hubspot-start`.\n\nMCP: `oxygen_hubspot_connection_start`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"return_to":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_hubspot_connection_start"],"x-oxygen-cli-command":"oxygen integrations hubspot-start"}},"/api/cli/integrations/openrouter/models":{"get":{"operationId":"integrations.openrouter_models","tags":["Integrations"],"summary":"Integrations openrouter models","description":"Read model and pricing metadata using this workspace's connected OpenRouter account; credentials are never returned.\n\nCLI: `oxygen integrations openrouter-models`.\n\nMCP: `oxygen_openrouter_models`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_openrouter_models"],"x-oxygen-cli-command":"oxygen integrations openrouter-models"}},"/api/cli/integrations/status":{"get":{"operationId":"integrations.status","tags":["Integrations"],"summary":"Integrations status","description":"Read active connection counts, sender connection state and the workspace's usable BYOK plan entitlement.\n\nCLI: `oxygen integrations status`.\n\nMCP: `oxygen_integration_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_integration_status"],"x-oxygen-cli-command":"oxygen integrations status"}},"/api/cli/integrations/test":{"post":{"operationId":"postIntegrationsTest","tags":["Integrations"],"summary":"Test Integration Connection","description":"Re-validates a stored integration API key against the provider (cheap read probe, zero credits) and heals the connection back to active/healthy when it passes. Use after the user fixed or rotated a credential — the self-serve recovery for connections stuck in status 'error' (benched) or health 'degraded' (missing key scopes) without re-pasting the key.\n\nMCP: `oxygen_integrations_test`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{},"connection_id":{"type":"string","description":"Test a specific connected account when several exist. Omit to test the default/most recent connection.","minLength":1,"maxLength":200},"integrationId":{},"integration_id":{"type":"string","description":"Integration id, such as 'slack'.","minLength":1,"maxLength":80}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_integrations_test"]}},"/api/cli/knowledge/agent":{"get":{"operationId":"getKnowledgeAgent","tags":["Knowledge"],"summary":"Get Knowledge Synthesis Agent Config","description":"Read scheduled synthesis config: enabled (default off), cadence hours and daily managed-credit cap. When enabled, sources become working learnings on schedule; canonical/typed-core edits require proposals.\n\nMCP: `oxygen_knowledge_agent_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"crm_index","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_agent_get"]},"post":{"operationId":"postKnowledgeAgent","tags":["Knowledge"],"summary":"Configure Knowledge Synthesis Agent","description":"Configure unattended synthesis of sources into working learnings, with a UTC-day spend cap. Canonical edits require human-approved proposals. Omitted fields preserve values. Defaults: disabled, 24h, 100 credits/day. Internal config write.\n\nMCP: `oxygen_knowledge_agent_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"cadence_hours":{"type":"number","description":"Hours between synthesis cycles (clamped 1-168).","minimum":1,"maximum":168},"crm_index":{},"enabled":{"type":"boolean","description":"Turn unattended synthesis on or off."},"max_credits_per_day":{"type":"number","description":"Managed-credit budget per UTC day (clamped 0-10,000).","minimum":0,"maximum":10000}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_agent_set"]}},"/api/cli/knowledge/bootstrap":{"post":{"operationId":"postKnowledgeBootstrap","tags":["Knowledge"],"summary":"Bootstrap Company Knowledge","description":"Read saved company research with status=true, or preview the manual pass with mode=dry_run. Manual live research is customer-funded, requires max_credits and saves cited company facts and GTM hypotheses. Automatic signup research is a separate platform-funded pass and may enrich the creator. Check status first; a prior marker blocks repeats without force=true.\n\nMCP: `oxygen_knowledge_bootstrap`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Company domain; defaults to the recorded workspace domain. Preview asks for one when none is available.","minLength":1,"maxLength":200},"force":{"type":"boolean","description":"Re-arm past any prior marker. With mode=dry_run it only previews the re-arm; nothing is cleared or written. With mode=live it replaces the marker and spends again."},"linkedin_url":{"type":"string","description":"Optional direct-lookup company LinkedIn URL; returned website must match the domain.","minLength":1,"maxLength":300},"max_credits":{"type":"number","description":"Hard credit ceiling for the whole pass. Required when mode=live; clamped server-side to 150.","exclusiveMinimum":0},"mode":{"type":"string","enum":["dry_run","live"],"description":"dry_run (default) previews the manual pass and cost for free; live bills, writes the profile and page, and requires max_credits."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_bootstrap"]}},"/api/cli/knowledge/files/archive":{"post":{"operationId":"postKnowledgeFilesArchive","tags":["Knowledge"],"summary":"Knowledge File","description":"List/read original Knowledge files or upsert/archive with revision CAS (0=create). Use text, property_patch, or bytes_base64. Canonical edits may need approval. Get supports ranges.\n\nMCP: `oxygen_knowledge_file`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"bytesBase64":{},"cursor":{"type":"string"},"expectedFileRevision":{},"id":{"type":"string"},"limit":{"type":"number","minimum":0},"mountId":{},"path":{"type":"string"},"propertyPatch":{},"revision":{"type":"number","minimum":0},"text":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_file"]}},"/api/cli/knowledge/files/download":{"get":{"operationId":"knowledge.files.download","tags":["Knowledge"],"summary":"Knowledge files download","description":"Download exact bytes for one entitled Knowledge file or pinned revision.\n\nMCP: `oxygen_knowledge_file`, `oxygen_knowledge_file_download`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"query","required":true,"schema":{"type":"string"}},{"name":"revision","in":"query","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_file","oxygen_knowledge_file_download"]}},"/api/cli/knowledge/files/get":{"get":{"operationId":"knowledge.files.get","tags":["Knowledge"],"summary":"Knowledge files get","description":"Read one entitled Knowledge file's metadata and bounded text when supported; revision pins historical content.\n\nMCP: `oxygen_knowledge_file`, `oxygen_knowledge_file_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"query","required":true,"schema":{"type":"string"}},{"name":"revision","in":"query","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_file","oxygen_knowledge_file_get"]}},"/api/cli/knowledge/files/list":{"get":{"operationId":"knowledge.files.list","tags":["Knowledge"],"summary":"Knowledge files list","description":"List files in one entitled Knowledge repository mount; returns metadata and a bounded cursor.\n\nMCP: `oxygen_knowledge_file`, `oxygen_knowledge_files_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"mountId","in":"query","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_file","oxygen_knowledge_files_list"]}},"/api/cli/knowledge/files/upsert":{"post":{"operationId":"postKnowledgeFilesUpsert","tags":["Knowledge"],"summary":"Knowledge File","description":"List/read original Knowledge files or upsert/archive with revision CAS (0=create). Use text, property_patch, or bytes_base64. Canonical edits may need approval. Get supports ranges.\n\nMCP: `oxygen_knowledge_file`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"bytesBase64":{},"cursor":{"type":"string"},"expectedFileRevision":{},"id":{"type":"string"},"limit":{"type":"number","minimum":0},"mountId":{},"path":{"type":"string"},"propertyPatch":{},"revision":{"type":"number","minimum":0},"text":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_file"]}},"/api/cli/knowledge/folders":{"get":{"operationId":"getKnowledgeFolders","tags":["Knowledge"],"summary":"List Knowledge Folders","description":"Lists folders and pages, including empty folders. Omit view for the existing explorer; view=folders returns id/name/parentId in bounded windows. Follow next_cursor; no sharing/permission metadata.\n\nMCP: `oxygen_knowledge_folders_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_folders_list"]}},"/api/cli/knowledge/folders/create":{"post":{"operationId":"postKnowledgeFoldersCreate","tags":["Knowledge"],"summary":"Create Knowledge Folder","description":"Creates a persistent folder. Place files with oxygen_knowledge_page_upsert page.folderId. Free internal write.\n\nMCP: `oxygen_knowledge_folders_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Folder name.","minLength":1,"maxLength":120},"parentId":{"type":"string","description":"Parent folder UUID. Omit for root."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_folders_create"]}},"/api/cli/knowledge/folders/move":{"post":{"operationId":"postKnowledgeFoldersMove","tags":["Knowledge"],"summary":"Move Knowledge Folder","description":"Moves a folder and its contents. Page slugs stay stable. Free internal write.\n\nMCP: `oxygen_knowledge_folders_move`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Folder UUID."},"parentId":{"type":"string","description":"Destination folder UUID, or root."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_folders_move"]}},"/api/cli/knowledge/graph":{"get":{"operationId":"getKnowledgeGraph","tags":["Knowledge"],"summary":"Read Knowledge Graph","description":"Returns page nodes and [[wikilink]] edges, including unresolved targets. Optional center (slug or id) limits to a local neighborhood; depth (1-3) sets hops. Fill gaps with oxygen_knowledge_page_upsert.\n\nMCP: `oxygen_knowledge_graph`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_graph"]}},"/api/cli/knowledge/index":{"get":{"operationId":"getKnowledgeIndex","tags":["Knowledge"],"summary":"Knowledge Graph Index","description":"Free active/draft catalog with page links/revisions. Traverse next_cursor for local/shared notes; live keyset, not a snapshot. Degree counts resolved links, not citations. semantic.budget is Oxygen-funded. Open relevant pages and cite revisions.\n\nMCP: `oxygen_knowledge_index`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_index"]}},"/api/cli/knowledge/lint":{"get":{"operationId":"getKnowledgeLint","tags":["Knowledge"],"summary":"Lint Knowledge Graph","description":"Free structural health report: orphan/dead-end pages, unresolved links, contradictions, competing canonical copy, missing metadata, duplicate/oversized/stale pages, empty seed hubs, decisions missing reversal conditions and aged proposals. Seed stubs are separate from orphans. Stale includes 90+ days untouched or newer sources; SUPERSEDED learnings require knowledge synthesize. Fix with oxygen_knowledge_page_upsert. relink=true rebuilds links after bulk edits; lint again afterward.\n\nMCP: `oxygen_knowledge_lint`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_lint"]}},"/api/cli/knowledge/lint/relink":{"post":{"operationId":"postKnowledgeLintRelink","tags":["Knowledge"],"summary":"Lint Knowledge Graph","description":"Free structural health report: orphan/dead-end pages, unresolved links, contradictions, competing canonical copy, missing metadata, duplicate/oversized/stale pages, empty seed hubs, decisions missing reversal conditions and aged proposals. Seed stubs are separate from orphans. Stale includes 90+ days untouched or newer sources; SUPERSEDED learnings require knowledge synthesize. Fix with oxygen_knowledge_page_upsert. relink=true rebuilds links after bulk edits; lint again afterward.\n\nMCP: `oxygen_knowledge_lint`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"slugs":{"type":"array","items":{"type":"string"},"description":"Pages to relink when relink=true; omit to relink all pages."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_lint"]}},"/api/cli/knowledge/log":{"get":{"operationId":"getKnowledgeLog","tags":["Knowledge"],"summary":"List Knowledge Graph History","description":"Read append-only wiki history: seeds, page writes, pins, filings, notes and decisions, newest first. Read-only, 0 credits. Skim before filing more; pass nextCursor as cursor for older entries.\n\nMCP: `oxygen_knowledge_log_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_log_list"]}},"/api/cli/knowledge/log/append":{"post":{"operationId":"postKnowledgeLogAppend","tags":["Knowledge"],"summary":"Append to Knowledge Graph History","description":"Append a wiki filing. Pair with oxygen_knowledge_page_upsert when filing an answer; reference its slug.\n\nMCP: `oxygen_knowledge_log_append`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Structured detail.","additionalProperties":true},"event":{"type":"string","enum":["note","query_filed","decision"],"description":"Filing kind: note (free-form observation), query_filed (an answer you filed back into a page), or decision."},"slug":{"type":"string","description":"Page slug, if any.","minLength":1,"maxLength":120},"summary":{"type":"string","description":"What was filed or decided.","maxLength":1000}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_log_append"]}},"/api/cli/knowledge/pages":{"post":{"operationId":"postKnowledgePages","tags":["Knowledge"],"summary":"List Knowledge Graph Pages","description":"Index pages filtered by type, status or tags. Read matching pages with oxygen_knowledge_page_get before answering; cite slugs.\n\nMCP: `oxygen_knowledge_page_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"type":"number","description":"Defaults to 100.","minimum":1,"maximum":500},"status":{"type":"string","enum":["draft","active","archived"]},"tags":{"type":"array","description":"Tags that returned pages must contain.","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":20},"type":{"type":"string","enum":["playbook","strategy","campaign","positioning","persona","competitor","research_note","message_playbook","proposed_playbook_bullet","voice","brand","other","entity","topic","source_summary","report","schema"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_page_list"]}},"/api/cli/knowledge/pages/archive":{"post":{"operationId":"knowledge.pages.archive","tags":["Knowledge"],"summary":"Knowledge page archive","description":"Archive a knowledge page; content/history remain, links become unresolved. Pass expected_revision for the version you reviewed.\n\nMCP: `oxygen_knowledge_page_archive`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"id":{"type":"string"},"expected_revision":{"type":"integer","minimum":1}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_page_archive"]}},"/api/cli/knowledge/pages/get":{"get":{"operationId":"getKnowledgePagesGet","tags":["Knowledge"],"summary":"Get Knowledge Graph Page","description":"Free page read. Metadata defaults; body follows revision/hash-bound next_cursor. Select data, data_keys/path, links or sources; full must fit. Cite slug/revision. Shared grants read current revision only.\n\nMCP: `oxygen_knowledge_page_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_page_get"]}},"/api/cli/knowledge/pages/pin":{"post":{"operationId":"postKnowledgePagesPin","tags":["Knowledge"],"summary":"Pin Knowledge Graph Page","description":"Pins an existing page as its type's canonical page (only voice, brand and positioning pins are injected into AI copy); canonical=false unpins. Address by slug or id; no body or content revision. Sensitive types (voice, brand, positioning) always file a proposal for oxygen_knowledge_proposal_decide. To create-and-pin, use oxygen_knowledge_page_upsert with canonical=true.\n\nMCP: `oxygen_knowledge_page_pin`, `oxygen_knowledge_page_upsert`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{},"canonical":{"type":"boolean","description":"Pin as the canonical default for its type (default true). Pass false to unpin (clear the canonical default for this type)."},"id":{"type":"string","description":"Page UUID.","minLength":1},"slug":{"type":"string","description":"Natural key; preferred over id.","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_page_pin","oxygen_knowledge_page_upsert"]}},"/api/cli/knowledge/pages/restore":{"post":{"operationId":"knowledge.pages.restore","tags":["Knowledge"],"summary":"Knowledge page restore","description":"Restore a knowledge page to an earlier revision as a new revision; history is kept. Pass expected_revision to refuse if the page changed since. Sensitive pages still need approval.\n\nMCP: `oxygen_knowledge_page_restore`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"id":{"type":"string"},"revision":{"type":"integer","minimum":1},"expected_revision":{"type":"integer","minimum":1}},"required":["revision"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_page_restore"]}},"/api/cli/knowledge/pages/revisions":{"get":{"operationId":"getKnowledgePagesRevisions","tags":["Knowledge"],"summary":"List Knowledge Graph Page Revisions","description":"Page history, newest first, with metadata, actor and timestamp; no bodies. Address by slug or id. Open a snapshot with oxygen_knowledge_page_revision_get.\n\nMCP: `oxygen_knowledge_page_revisions_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_page_revisions_list"]}},"/api/cli/knowledge/pages/revisions/get":{"get":{"operationId":"getKnowledgePagesRevisionsGet","tags":["Knowledge"],"summary":"Get Knowledge Graph Page Revision","description":"Read full historical page metadata, Markdown and data by slug or id plus revision from oxygen_knowledge_page_revisions_list.\n\nMCP: `oxygen_knowledge_page_revision_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_page_revision_get"]}},"/api/cli/knowledge/pages/upsert":{"post":{"operationId":"postKnowledgePagesUpsert","tags":["Knowledge"],"summary":"Upsert Knowledge Graph Page","description":"Free internal write: create/update by slug/id or title. Check duplicates; cite [[slug]]. Sensitive canonical edits: knowledge_approval_required; use oxygen_knowledge_proposal_decide. Pair filings with oxygen_knowledge_log_append.\n\nMCP: `oxygen_knowledge_page_upsert`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Never bypasses proposal approval."},"body":{},"createOnly":{},"data":{},"expected_revision":{},"folderId":{},"id":{},"page":{"type":"object","properties":{"id":{"type":"string","description":"Existing page UUID."},"folderId":{"type":"string","description":"Folder UUID; root clears; omit preserves. Moves add a revision, updating data.knowledge_folder_id."},"createOnly":{"type":"boolean","description":"Refuse an existing slug."},"slug":{"type":"string","description":"Immutable; omitted: title's slug, updating that page.","maxLength":120},"type":{"type":"string","enum":["playbook","strategy","campaign","positioning","persona","competitor","research_note","message_playbook","proposed_playbook_bullet","voice","brand","other","entity","topic","source_summary","report","schema"],"description":"Default: other."},"title":{"type":"string","description":"Required on create.","minLength":1,"maxLength":240},"status":{"type":"string","enum":["draft","active","archived"],"description":"Default active. Restore draft + expected_revision; omitted body is retained."},"tags":{"type":"array","description":"Lowercased.","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":50},"summary":{"type":"string","description":"List/graph abstract.","maxLength":1000},"body":{"type":"string","description":"Markdown with [[slug]] wikilinks.","maxLength":120000},"data":{"type":"object","description":"Frontmatter JSON.","additionalProperties":true},"expected_revision":{"type":"number","description":"Reject a different revision (knowledge_page_conflict).","minimum":0}},"additionalProperties":false},"slug":{},"status":{},"summary":{},"tags":{},"title":{},"type":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_knowledge_page_upsert"]}},"/api/cli/knowledge/profile":{"get":{"operationId":"getKnowledgeProfile","tags":["Knowledge"],"summary":"Get GTM Context Profile","description":"Reads durable workspace GTM memory: company, offering, ICP, market, GTM stack, and custom fields. Call this before planning lead sourcing, campaign strategy, ICP decisions, outbound copy, positioning, or prospect qualification.\n\nMCP: `oxygen_context_profile_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_context_profile_get"]}},"/api/cli/knowledge/profile/update":{"post":{"operationId":"postKnowledgeProfileUpdate","tags":["Knowledge"],"summary":"Update GTM Context Profile","description":"Updates durable workspace GTM memory. Provide only sections that changed; section objects shallow-merge with existing profile sections and every update creates a revision snapshot.\n\nMCP: `oxygen_context_profile_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"data":{},"profile":{"type":"object","description":"Company profile patch with any of company, offering, icp, market, gtm_stack, or custom.","properties":{"company":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"offering":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"icp":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"market":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"gtm_stack":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true},"custom":{"type":"object","description":"Omitted keys unchanged; provided keys shallow-merge.","additionalProperties":true}},"additionalProperties":false},"summary":{"type":"string","description":"Concise current-state summary for humans and agents.","maxLength":4000}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_context_profile_update"]}},"/api/cli/knowledge/proposals":{"get":{"operationId":"getKnowledgeProposals","tags":["Knowledge"],"summary":"List Knowledge Graph Proposals","description":"Review pending captured Knowledge changes. Default open; status decided/all reads history. Omit window controls for legacy full patches. summary + next_cursor traverses the live queue; exact proposal + value + path reads raw captured JSON with next_value_cursor. Decide with oxygen_knowledge_proposal_decide.\n\nMCP: `oxygen_knowledge_proposals_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_proposals_list"]}},"/api/cli/knowledge/proposals/approve":{"post":{"operationId":"postKnowledgeProposalsApprove","tags":["Knowledge"],"summary":"Decide Knowledge Graph Proposal","description":"Approves or rejects an open Knowledge Graph proposal by its id or proposal slug. Approve applies the captured patch to the target page (new revision, links recomputed, logged); reject archives the proposal and leaves the target untouched. If the target page changed since the proposal was filed, approve fails with knowledge_proposal_stale — re-review the diff, then pass force=true to apply anyway. This publishes sensitive canonical content: confirm the decision with the user first.\n\nMCP: `oxygen_knowledge_proposal_decide`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","description":"Approve even though the target page changed since the proposal was filed (after re-review). Ignored on reject."},"proposal_id":{},"slug":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_knowledge_proposal_decide"]}},"/api/cli/knowledge/proposals/reject":{"post":{"operationId":"postKnowledgeProposalsReject","tags":["Knowledge"],"summary":"Decide Knowledge Graph Proposal","description":"Approves or rejects an open Knowledge Graph proposal by its id or proposal slug. Approve applies the captured patch to the target page (new revision, links recomputed, logged); reject archives the proposal and leaves the target untouched. If the target page changed since the proposal was filed, approve fails with knowledge_proposal_stale — re-review the diff, then pass force=true to apply anyway. This publishes sensitive canonical content: confirm the decision with the user first.\n\nMCP: `oxygen_knowledge_proposal_decide`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","description":"Approve even though the target page changed since the proposal was filed (after re-review). Ignored on reject."},"proposal_id":{},"slug":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_knowledge_proposal_decide"]}},"/api/cli/knowledge/repositories/action":{"post":{"operationId":"postKnowledgeRepositoriesAction","tags":["Knowledge"],"summary":"Knowledge Repository","description":"Manage GitHub Knowledge mounts after GitHub auth. Preview before connect; two_way permits branch writes. Conflict resolves pin the reviewed revision and SHA. 0 credits.\n\nMCP: `oxygen_knowledge_repository`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["list","repositories","branches","preview","connect","sync","pause","resume","disconnect","conflicts","resolve"]},"approved":{"type":"boolean"},"branch":{"type":"string"},"connectionId":{},"decision":{"type":"string","enum":["oxygen","github","merged"]},"expectedLocalRevision":{},"expectedRemoteSha":{},"id":{},"mode":{"type":"string","enum":["import","two_way"]},"mountId":{},"path":{"type":"string"},"previewToken":{},"repositoryId":{},"rootPath":{},"text":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_repository"]}},"/api/cli/knowledge/repositories/conflicts":{"post":{"operationId":"postKnowledgeRepositoriesConflicts","tags":["Knowledge"],"summary":"Knowledge Repository","description":"Manage GitHub Knowledge mounts after GitHub auth. Preview before connect; two_way permits branch writes. Conflict resolves pin the reviewed revision and SHA. 0 credits.\n\nMCP: `oxygen_knowledge_repository`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["list","repositories","branches","preview","connect","sync","pause","resume","disconnect","conflicts","resolve"]},"approved":{"type":"boolean"},"branch":{"type":"string"},"connectionId":{},"decision":{"type":"string","enum":["oxygen","github","merged"]},"expectedLocalRevision":{},"expectedRemoteSha":{},"id":{},"mode":{"type":"string","enum":["import","two_way"]},"mountId":{},"path":{"type":"string"},"previewToken":{},"repositoryId":{},"rootPath":{},"text":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_repository"]}},"/api/cli/knowledge/repositories/connect":{"post":{"operationId":"postKnowledgeRepositoriesConnect","tags":["Knowledge"],"summary":"Knowledge Repository","description":"Manage GitHub Knowledge mounts after GitHub auth. Preview before connect; two_way permits branch writes. Conflict resolves pin the reviewed revision and SHA. 0 credits.\n\nMCP: `oxygen_knowledge_repository`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["list","repositories","branches","preview","connect","sync","pause","resume","disconnect","conflicts","resolve"]},"approved":{"type":"boolean"},"branch":{"type":"string"},"connectionId":{},"decision":{"type":"string","enum":["oxygen","github","merged"]},"expectedLocalRevision":{},"expectedRemoteSha":{},"id":{},"mode":{"type":"string","enum":["import","two_way"]},"mountId":{},"path":{"type":"string"},"previewToken":{},"repositoryId":{},"rootPath":{},"text":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_repository"]}},"/api/cli/knowledge/repositories/list":{"post":{"operationId":"postKnowledgeRepositoriesList","tags":["Knowledge"],"summary":"Knowledge Repository","description":"Manage GitHub Knowledge mounts after GitHub auth. Preview before connect; two_way permits branch writes. Conflict resolves pin the reviewed revision and SHA. 0 credits.\n\nMCP: `oxygen_knowledge_repository`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["list","repositories","branches","preview","connect","sync","pause","resume","disconnect","conflicts","resolve"]},"approved":{"type":"boolean"},"branch":{"type":"string"},"connectionId":{},"decision":{"type":"string","enum":["oxygen","github","merged"]},"expectedLocalRevision":{},"expectedRemoteSha":{},"id":{},"mode":{"type":"string","enum":["import","two_way"]},"mountId":{},"path":{"type":"string"},"previewToken":{},"repositoryId":{},"rootPath":{},"text":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_repository"]}},"/api/cli/knowledge/repositories/preview":{"post":{"operationId":"postKnowledgeRepositoriesPreview","tags":["Knowledge"],"summary":"Knowledge Repository","description":"Manage GitHub Knowledge mounts after GitHub auth. Preview before connect; two_way permits branch writes. Conflict resolves pin the reviewed revision and SHA. 0 credits.\n\nMCP: `oxygen_knowledge_repository`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["list","repositories","branches","preview","connect","sync","pause","resume","disconnect","conflicts","resolve"]},"approved":{"type":"boolean"},"branch":{"type":"string"},"connectionId":{},"decision":{"type":"string","enum":["oxygen","github","merged"]},"expectedLocalRevision":{},"expectedRemoteSha":{},"id":{},"mode":{"type":"string","enum":["import","two_way"]},"mountId":{},"path":{"type":"string"},"previewToken":{},"repositoryId":{},"rootPath":{},"text":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_repository"]}},"/api/cli/knowledge/repositories/resolve":{"post":{"operationId":"postKnowledgeRepositoriesResolve","tags":["Knowledge"],"summary":"Knowledge Repository","description":"Manage GitHub Knowledge mounts after GitHub auth. Preview before connect; two_way permits branch writes. Conflict resolves pin the reviewed revision and SHA. 0 credits.\n\nMCP: `oxygen_knowledge_repository`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["list","repositories","branches","preview","connect","sync","pause","resume","disconnect","conflicts","resolve"]},"approved":{"type":"boolean"},"branch":{"type":"string"},"connectionId":{},"decision":{"type":"string","enum":["oxygen","github","merged"]},"expectedLocalRevision":{},"expectedRemoteSha":{},"id":{},"mode":{"type":"string","enum":["import","two_way"]},"mountId":{},"path":{"type":"string"},"previewToken":{},"repositoryId":{},"rootPath":{},"text":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_repository"]}},"/api/cli/knowledge/resolve":{"post":{"operationId":"postKnowledgeResolve","tags":["Knowledge"],"summary":"Resolve Workspace GTM Context","description":"Resolves workspace context and assets. purpose='onboarding' adds a research brief, inferred GTM hypotheses (user corrections win), workspace campaigns, data and access, and plays to offer; first tell the user what you are checking.\n\nMCP: `oxygen_context_resolve`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"asset_status":{"type":"string","enum":["draft","active","archived","all"],"description":"Defaults to active."},"asset_types":{"type":"array","items":{"type":"string","enum":["playbook","strategy","campaign","positioning","brand","voice","persona","competitor","research_note","message_playbook","proposed_playbook_bullet","other"]},"maxItems":8},"include_archived":{"type":"boolean","description":"If true, includes archived assets when asset_status is omitted."},"max_assets":{"type":"number","description":"Defaults to 10.","minimum":0,"maximum":50},"purpose":{"type":"string","enum":["general","onboarding","lead_sourcing","qualification","outbound_copy","workflow_design"],"description":"GTM task this context supports. Defaults to general."},"require_ready":{"type":"boolean","description":"If true, returns a conflict error when required context sections are missing."},"tags":{"type":"array","description":"Tags that all returned assets must contain.","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":20}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_context_resolve"]}},"/api/cli/knowledge/search":{"post":{"operationId":"postKnowledgeSearch","tags":["Knowledge"],"summary":"Search Knowledge Graph","description":"Free wiki search: hybrid when enabled (platform-funded allowance), else keywords. Check match_type/semantic_status. Quotes/OR/exclusions stay lexical. Non-archived unless status is set. Open oxygen_knowledge_page_get; cite revisions and search before creating duplicates.\n\nMCP: `oxygen_knowledge_search`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"type":"number","description":"Defaults to 100.","minimum":1,"maximum":500},"query":{"type":"string","description":"Search text. websearch syntax: \"quoted phrase\", term OR term, -exclude.","minLength":1},"sources":{},"status":{"type":"string","enum":["draft","active","archived"],"description":"Defaults to every non-archived status."},"tags":{"type":"array","description":"Tags that returned pages must contain.","items":{"type":"string","minLength":1,"maxLength":80},"maxItems":20},"type":{"type":"string","enum":["playbook","strategy","campaign","positioning","persona","competitor","research_note","message_playbook","proposed_playbook_bullet","voice","brand","other","entity","topic","source_summary","report","schema"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_search"]}},"/api/cli/knowledge/seed":{"post":{"operationId":"postKnowledgeSeed","tags":["Knowledge"],"summary":"Seed Knowledge Graph Scaffold","description":"Ensure the starter ICP and Offers draft pages exist. Idempotent; preserves edits. Also runs on onboarding and first sync. Returns scaffold state.\n\nMCP: `oxygen_knowledge_seed`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_seed"]}},"/api/cli/knowledge/sync/delta":{"post":{"operationId":"knowledge.sync.delta","tags":["Knowledge"],"summary":"Knowledge sync delta","description":"Sync complete wiki pages/tombstones; first call may seed missing starter pages. Follow next_cursor; an oversized page is refused without skipping. 0 credits.\n\nCLI: `oxygen knowledge sync-delta`.\n\nMCP: `oxygen_knowledge_sync_delta`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cursor":{"type":"string","minLength":1,"maxLength":256},"limit":{"type":"integer","minimum":1,"maximum":200},"max_chars":{"type":"integer","minimum":1000,"maximum":48000,"description":"Response-envelope character cap; complete pages only. A single oversized page is refused; none is skipped. Surface cap applies."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_knowledge_sync_delta"],"x-oxygen-cli-command":"oxygen knowledge sync-delta"}},"/api/cli/knowledge/sync/manifest":{"post":{"operationId":"knowledge.sync.manifest","tags":["Knowledge"],"summary":"Knowledge sync manifest","description":"Read complete wiki revision/hash metadata. has_more/truncated mean more pages, not cut entries. last_cursor marks the last returned page; next_cursor resumes when more remain. Live keyset, not a snapshot.\n\nCLI: `oxygen knowledge sync-manifest`.\n\nMCP: `oxygen_knowledge_sync_manifest`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cursor":{"type":"string","minLength":1,"maxLength":256},"limit":{"type":"integer","minimum":1,"maximum":200},"max_chars":{"type":"integer","minimum":1000,"maximum":48000,"description":"Response-envelope character cap; complete pages only. A single oversized page is refused; none is skipped. Surface cap applies."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_knowledge_sync_manifest"],"x-oxygen-cli-command":"oxygen knowledge sync-manifest"}},"/api/cli/knowledge/synthesize":{"post":{"operationId":"postKnowledgeSynthesize","tags":["Knowledge"],"summary":"Synthesize Voice or Campaign Learnings","description":"Runs one low-cost AI synthesis of workspace evidence into durable knowledge; every run spends a few managed AI credits, the preview included, and reports credits_used. kind='voice' learns your writing voice from your own SENT WhatsApp/LinkedIn messages and saves it; once its pin proposal is approved (oxygen_knowledge_proposal_decide) it is your canonical voice, which grounds message, reply, sequence and post drafts, Oxygent chats and message-writing AI columns. kind='campaign_learnings' distills auto-filed outreach outcomes (reply classifications, bounces, opt-outs, won/lost deals) plus sequence stats into a campaign-learnings wiki page; Oxygent chats, drafts and AI columns retrieve it where Knowledge retrieval is on. approved=false (default) previews; approved=true writes (learnings = a logged, revertible page revision; voice = saved + a pin proposal). approved=true without body synthesizes again (a second charge and new text): to keep what a preview showed, pass its body, or your edit, with approved=true, which makes no AI call. Fewer than 3 sent messages stops before the AI call with insufficient_source_messages and no charge.\n\nMCP: `oxygen_context_synthesize`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"false (default) previews without saving; true writes the result."},"body":{"type":"string","description":"With approved=true, save this edited markdown instead of re-synthesizing."},"kind":{"type":"string","enum":["voice","campaign_learnings"]},"limit":{"type":"number","description":"voice only: recent sent messages to learn from. Defaults to 200.","minimum":1,"maximum":200},"max_credits":{"type":"number","minimum":0,"description":"Hard cap OXYGEN enforces: the call is charged exactly its estimate, never more than this. A higher estimate is refused before any AI call, nothing charged, and the refusal reports the estimate (0 shows it free). Not needed with approved=true and body (no AI call)."},"sender":{},"sequence":{"type":"string","description":"campaign_learnings only: sequence id to scope onto that sequence's learnings page. Omit for the org-wide outreach-learnings page."},"title":{"type":"string","description":"Title for a newly created asset/page."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_context_synthesize"]}},"/api/cli/lead-sourcing/audit":{"post":{"operationId":"postLeadSourcingAudit","tags":["Lead sourcing"],"summary":"Audit Lead Sourcing","description":"Audits a sourced lead table against a LeadSourcingSpec or prompt: title fit, geography fit, account qualification, hard-exclude leakage, contact coverage, duplicates, and enrichment waste.\n\nMCP: `oxygen_lead_sourcing_audit`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{},"slug":{},"source_prompt":{},"spec":{"type":"object","description":"Compiled LeadSourcingSpec. If omitted, pass spec_prompt.","additionalProperties":true},"spec_prompt":{"type":"string","description":"Prompt to compile into a LeadSourcingSpec when spec is not provided.","minLength":1,"maxLength":20000},"table":{"type":"string","description":"Table id or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_lead_sourcing_audit"]}},"/api/cli/lead-sourcing/plan":{"post":{"operationId":"postLeadSourcingPlan","tags":["Lead sourcing"],"summary":"Plan Lead Sourcing","description":"Compiles a natural-language ICP into an account-first lead sourcing plan with explicit filters, segment confidence, risks, attrition estimate, dedupe policy, enrichment gates, and the active workspace company/domain confirmation. The account-finding step delegates to oxygen_companies_search_plan/run — run company search there to source the accounts. Confirm context_confirmation before table-ingestions or blitzapi.people_search.\n\nMCP: `oxygen_lead_sourcing_plan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"materializePreview":{},"materialize_preview":{"type":"boolean","description":"When true, create an Oxygen preview table for the plan. Defaults to false."},"prompt":{"type":"string","description":"Natural-language ICP and lead requirements.","minLength":1,"maxLength":20000},"source_prompt":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_lead_sourcing_plan"]}},"/api/cli/limits":{"get":{"operationId":"getLimits","tags":["Limits"],"summary":"Show Plan-tier Limits","description":"Plan/storage summary; yearly prices and terms: oxygen_billing_balance. Sections: capacity=largest reconciled Table; pricing=monthly prices/capacity; plan=one band; rate/spend/sending. Named trims; narrow section. Planned capacity is not headroom.\n\nMCP: `oxygen_limits_show`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"section","in":"query","required":false,"schema":{"type":"string","enum":["summary","capacity","plan","pricing","api","webhooks","spend","sending","workflow","all"],"description":"summary by default on MCP; capacity names the largest reconciled Table."}},{"name":"band","in":"query","required":false,"schema":{"type":"string","enum":["free","49","99","199","499","999","1999"],"description":"plan/all only; selecting a band defaults to plan."}},{"name":"max_chars","in":"query","required":false,"schema":{"type":"integer","minimum":1000,"maximum":10000,"description":"Projection character ceiling; omissions are named."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_limits_show"]}},"/api/cli/limits/provider":{"get":{"operationId":"limits.provider.get","tags":["Limits"],"summary":"Limits provider list","description":"Read provider request limits and BYOK warning defaults. MCP defaults to bounded summary pages; follow paging.next_offset with the same filter. HTTP/CLI omit pagination for the full legacy list. 0 credits.\n\nMCP: `oxygen_provider_limits_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"provider","in":"query","required":false,"schema":{"type":"string","minLength":1,"description":"Provider ID, e.g. hubspot or leadmagic."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"description":"Saved policies per page; omit for the legacy full list."}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Current-policy offset; repeat the same provider filter. Concurrent edits may shift rows."}},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["full","summary"],"description":"Full keeps native fields; summary names omitted evidence fields in projection. HTTP/CLI default full."}},{"name":"max_chars","in":"query","required":false,"schema":{"type":"integer","minimum":2000,"maximum":40000,"description":"Native context window; MCP caps it at 10000 (external) or 4000 (built-in). Paging.next_offset follows the last exposed row."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_provider_limits_list"]},"post":{"operationId":"limits.provider.set","tags":["Limits"],"summary":"Limits provider set","description":"Set an enforced provider request limit; admin or owner only. Approve the exact provider, operation and window: raising a cap may permit more provider use. 0 credits.\n\nMCP: `oxygen_provider_limits_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","minLength":1,"description":"Provider ID, e.g. hubspot or leadmagic."},"operation":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"Exact operation; omit to target the provider-wide policy, not every operation policy."},"limit":{"type":"integer","minimum":1,"description":"Enforced calls allowed per window."},"window_seconds":{"type":"integer","minimum":1,"description":"Window in seconds; 86400 sets an explicit daily policy."}},"required":["provider","limit","window_seconds"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_provider_limits_set"]},"delete":{"operationId":"limits.provider.delete","tags":["Limits"],"summary":"Limits provider delete","description":"Clear one provider request-limit override; admin or owner only. Approve the exact selector. Other operation overrides remain; the provider returns to its defaults, whose BYOK threshold may be observe-only. 0 credits.\n\nMCP: `oxygen_provider_limits_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"provider","in":"query","required":true,"schema":{"type":"string","minLength":1,"description":"Provider ID, e.g. hubspot or leadmagic."}},{"name":"operation","in":"query","required":false,"schema":{"type":"string","description":"Exact operation; omit to target the provider-wide policy, not every operation policy."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_provider_limits_delete"]}},"/api/cli/linkedin/connections/import":{"get":{"operationId":"linkedin.connections.import_status","tags":["Linkedin"],"summary":"Linkedin connections import status","description":"Read the durable LinkedIn connections import status and target Table.\n\nCLI: `oxygen linkedin connections import-status`.\n\nMCP: `oxygen_linkedin_connections_import_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_connections_import_status"],"x-oxygen-cli-command":"oxygen linkedin connections import-status"},"post":{"operationId":"postLinkedinConnectionsImport","tags":["Linkedin"],"summary":"Import LinkedIn Connections","description":"Reads a LinkedIn account's 1st-degree connections into an enrichable Clay-like workspace table plus a deduped system-of-record mirror. Starts a slow durable background import dripping connections over many worker ticks under a conservative read budget (never bursts, never starves the sequencer) — poll oxygen_linkedin_connections_status. account = which sender (sender, connection, or Unipile account id; omit for every active LinkedIn account). table = existing table id/slug (omit to create/reuse 'LinkedIn Connections'). Stays fresh on its own: periodic background re-walks pick up new connections (rows dedupe on member id); re-running re-walks immediately. A read: no messages sent, no credits charged.\n\nMCP: `oxygen_linkedin_connections_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender account to import (sender id, connection id, or Unipile account id). Omit to import every active LinkedIn account."},"table":{"type":"string","description":"Optional existing workspace table (id or slug) to import into. Omit to create/reuse a 'LinkedIn Connections' table."},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_connections_import"]}},"/api/cli/linkedin/connections/invite":{"post":{"operationId":"postLinkedinConnectionsInvite","tags":["Linkedin"],"summary":"Send a LinkedIn Connection Invite","description":"Sends a LinkedIn connection invitation. This is a REAL external social action that consumes the account's daily invite quota (and respects its warm-up ramp): call once with approved=false (default) to preview, then again with approved=true to send. recipient is the member's LinkedIn provider id (ACo…) OR a profile URL / public identifier (resolved to the provider id on send). message is the optional invitation note (~300 chars). account selects which sender invites (sender id, connection id, or Unipile account id); omit for the org default. Invites are de-duplicated by the shipped verify-before-send check, so re-inviting someone already invited is a safe no-op.\n\nMCP: `oxygen_linkedin_send_invite`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Sender id, connection id, or Unipile account id."},"approved":{"type":"boolean","description":"Set true to actually send the invite. Omit/false returns a preview only."},"message":{"type":"string","description":"Optional invitation note (~300 chars max)."},"provider_id":{},"recipient":{"type":"string","description":"Recipient LinkedIn provider id (ACo…), profile URL, or public identifier."},"url":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_send_invite"]}},"/api/cli/linkedin/connections/invite/withdraw":{"post":{"operationId":"postLinkedinConnectionsInviteWithdraw","tags":["Linkedin"],"summary":"Withdraw Sent LinkedIn Invites","description":"Withdraws pending sent LinkedIn invitations. This is a REAL external social action gated preview→approved: call once with approved=false (default) to see which invitations would be withdrawn, then again with approved=true to withdraw them. Select targets with EITHER invitation_ids (an explicit array, from oxygen_linkedin_invites_sent) OR older_than_days (withdraw every pending invite older than N days, resolved server-side) — exactly one. Idempotent: withdrawing an invite that is already gone is reported as success. account selects the sender (sender id, connection id, or Unipile account id); omit for the org default.\n\nMCP: `oxygen_linkedin_invites_withdraw`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Sender id, connection id, or Unipile account id."},"approved":{"type":"boolean","description":"Set true to actually withdraw. Omit/false returns the resolved target list only."},"invitation_ids":{"type":"array","description":"Explicit invitation ids to withdraw (from oxygen_linkedin_invites_sent). Mutually exclusive with older_than_days.","items":{"type":"string"}},"older_than_days":{"type":"number","minimum":0,"description":"Withdraw every pending sent invite older than this many days. Mutually exclusive with invitation_ids."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_invites_withdraw"]}},"/api/cli/linkedin/connections/invites-sent":{"get":{"operationId":"getLinkedinConnectionsInvitesSent","tags":["Linkedin"],"summary":"List Sent LinkedIn Invites","description":"Live provider read of pending sent LinkedIn invitations; 0 credits, no provider write. CLI: oxygen linkedin invitations list --account <ref> --limit <n> --cursor <token> --json. Resume invitations.cursor unchanged with the same account; no cursor means stop, though a full page may need an empty final read. IDs support oxygen_linkedin_invites_withdraw; omit account for the org default.\n\nMCP: `oxygen_linkedin_invites_sent`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_invites_sent"]}},"/api/cli/linkedin/connections/status":{"get":{"operationId":"getLinkedinConnectionsStatus","tags":["Linkedin"],"summary":"LinkedIn Connections Import Status","description":"Shows the progress of LinkedIn connections imports: each drip's status, connections ingested so far, pages read, last error, plus a preview of the connections table and a deep-link to open it. account scopes to one sender (sender id, connection id, or Unipile account id); omit for every sender's import. Read-only.\n\nMCP: `oxygen_linkedin_connections_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Sender id, connection id, or Unipile account id."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_connections_status"]}},"/api/cli/linkedin/engagement":{"get":{"operationId":"getLinkedinEngagement","tags":["Linkedin"],"summary":"List Engagers on Own LinkedIn Post","description":"Reads reactors and commenters on a post the connected account owns, returning a de-duplicated people list for a Sequence or Table. Pages both sources to max_pages (default 5, max 20) x 100/page, one LinkedIn read each; truncated:true = a bound cut a still-full source: raise max_pages or use oxygen_engagement_harvest. Third-party posts: scraper.linkedin_post_reactions via oxygen_tools_search. account = the sender (default: workspace's).\n\nMCP: `oxygen_engagement_list_engagers`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Sender id, connection id, or Unipile account id."}},{"name":"include_comments","in":"query","required":false,"schema":{"type":"boolean","description":"Include commenters (default true)."}},{"name":"include_reactions","in":"query","required":false,"schema":{"type":"boolean","description":"Include reactors (default true)."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size, default 100 (provider max); per source: limit x max_pages."}},{"name":"max_pages","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"description":"Pages per source (default 5)."}},{"name":"post","in":"query","required":false,"schema":{"type":"string","description":"Composite social_id from oxygen_posts_get/users_posts (NOT the activity URN)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_engagement_list_engagers"]}},"/api/cli/linkedin/engagement/comment":{"post":{"operationId":"postLinkedinEngagementComment","tags":["Linkedin"],"summary":"Comment on a LinkedIn Post","description":"Comments on a LinkedIn post, or replies to a comment with comment_id. This is a REAL LinkedIn write that everyone can see and consumes the account's daily action quota: call once with approved=false (default) to preview, then again with approved=true to post the comment. post accepts the post social_id (numeric activity ids are normalized server-side). account selects which sender account comments (omit to use the org default); as_organization comments as a company page.\n\nMCP: `oxygen_engagement_comment`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Sender id, connection id, or Unipile account id."},"approved":{"type":"boolean","description":"Set true to actually post the comment. Omit/false returns a preview only."},"as_organization":{"type":"string","description":"LinkedIn organization id to comment as a company page."},"comment_id":{"type":"string","description":"Reply under this comment id instead of commenting on the post."},"external_link":{"type":"string","description":"URL to attach as a link preview on the comment."},"mentions":{"type":"array","description":"LinkedIn mentions array.","items":{"type":"object","additionalProperties":true,"properties":{}}},"post":{"type":"string","description":"Post id (social_id; numeric activity ids are normalized)."},"text":{"type":"string","description":"Comment text.","minLength":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_engagement_comment"]}},"/api/cli/linkedin/engagement/harvest":{"get":{"operationId":"getLinkedinEngagementHarvest","tags":["Linkedin"],"summary":"LinkedIn Engagement Harvest Status","description":"Shows the progress of a LinkedIn engagement harvest: the drip's status, engagers ingested so far, pages read, last error, plus the workspace table it fills (with a deep-link) and a preview of recently harvested engagers. account scopes to one sender; post scopes to one harvested post. Read-only.\n\nMCP: `oxygen_engagement_harvest_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Sender id, connection id, or Unipile account id."}},{"name":"post","in":"query","required":false,"schema":{"type":"string","description":"Optional post social_id to scope to."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_engagement_harvest_status"]},"post":{"operationId":"postLinkedinEngagementHarvest","tags":["Linkedin"],"summary":"Harvest a LinkedIn Post's Engagers into a Workspace Table","description":"Starts a durable background harvest of a post's reactors and commenters into a workspace table; no messages are sent. source=cookieless uses the managed scraper and requires post_url plus max_credits. source=unipile reads through account without Oxygen credits but uses its LinkedIn read allowance. post is the composite social_id from oxygen_posts_get/users_posts. recurring keeps polling for unseen engagers. Inspect progress with oxygen_engagement_harvest_status.\n\nMCP: `oxygen_engagement_harvest`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender account that keys the harvest (sender id, connection id, or Unipile account id)."},"account_id":{},"include_comments":{"type":"boolean","description":"Include commenters (default true)."},"include_reactions":{"type":"boolean","description":"Include reactors (default true)."},"max_credits":{"type":"number","minimum":1,"description":"Required for cookieless; caps managed scraper spend for this armed run. Choose it from the current descriptor and request-shaped dry-run estimate."},"post":{"type":"string","description":"Composite social_id from oxygen_posts_get/users_posts (or the public post URL for cookieless)."},"post_id":{},"post_url":{"type":"string","description":"Public LinkedIn post URL for the cookieless scraper (required when source=cookieless and post is not itself a URL)."},"recurring":{"type":"boolean","description":"Keep re-polling the newest pages for new engagers (default false = one walk)."},"source":{"type":"string","enum":["cookieless","unipile"],"description":"cookieless = managed scraper, no account-limit usage, spends credits (default when post_url is given); unipile = read via the connected account (free, account-metered)."},"url":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_engagement_harvest"]}},"/api/cli/linkedin/engagement/react":{"post":{"operationId":"postLinkedinEngagementReact","tags":["Linkedin"],"summary":"React to a LinkedIn Post","description":"Adds a reaction to a LinkedIn post, or to a comment with comment_id. This is a REAL LinkedIn write that everyone can see and consumes the account's daily action quota: call once with approved=false (default) to preview, then again with approved=true to react. reaction_type defaults to like. post accepts the post social_id. account selects which sender account reacts (omit to use the org default); as_organization reacts as a company page.\n\nMCP: `oxygen_engagement_react`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Sender id, connection id, or Unipile account id."},"approved":{"type":"boolean","description":"Set true to actually react. Omit/false returns a preview only."},"as_organization":{"type":"string","description":"LinkedIn organization id to react as a company page."},"comment_id":{"type":"string","description":"React to this comment id instead of the post."},"post":{"type":"string","description":"Post id (social_id)."},"reaction_type":{"type":"string","enum":["like","celebrate","support","love","insightful","funny"],"description":"Reaction kind (default like)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_engagement_react"]}},"/api/cli/linkedin/followers/import":{"get":{"operationId":"linkedin.followers.import_status","tags":["Linkedin"],"summary":"Linkedin followers import status","description":"Read the durable LinkedIn followers import status and target Table.\n\nCLI: `oxygen linkedin followers import-status`.\n\nMCP: `oxygen_linkedin_followers_import_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_followers_import_status"],"x-oxygen-cli-command":"oxygen linkedin followers import-status"},"post":{"operationId":"postLinkedinFollowersImport","tags":["Linkedin"],"summary":"Import LinkedIn Followers","description":"Reads a LinkedIn account's followers into an enrichable workspace table and a deduped mirror. Starts a SLOW durable background import that drips in over many worker ticks under a conservative read budget — it never bursts and never starves the sequencer's reads — so poll oxygen_linkedin_followers_status to watch the table accrue. account picks the sender (sender id, connection id, or Unipile account id); omit for every connected active account. table targets an existing table (id or slug); omit to create/reuse 'LinkedIn Followers'. After each full pass it periodically re-walks to pick up new followers (rows dedupe on the member id); re-running re-walks immediately. A read, not an outbound action: nothing is sent and no credits are charged.\n\nMCP: `oxygen_linkedin_followers_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender account to import (sender id, connection id, or Unipile account id). Omit to import every active LinkedIn account."},"table":{"type":"string","description":"Optional existing workspace table (id or slug) to import into. Omit to create/reuse a 'LinkedIn Followers' table."},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_followers_import"]}},"/api/cli/linkedin/followers/status":{"get":{"operationId":"getLinkedinFollowersStatus","tags":["Linkedin"],"summary":"LinkedIn Followers Import Status","description":"Shows the progress of LinkedIn followers imports: each drip's status, followers ingested so far, pages read, last error, plus a preview of the followers table and a deep-link to open it. account scopes to one sender (sender id, connection id, or Unipile account id); omit for every sender's import. Read-only.\n\nMCP: `oxygen_linkedin_followers_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Sender id, connection id, or Unipile account id."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_followers_status"]}},"/api/cli/linkedin/inbox/backfill":{"get":{"operationId":"linkedin.inbox.backfill_status","tags":["Linkedin"],"summary":"Linkedin inbox backfill status","description":"Read the durable LinkedIn inbox backfill status.\n\nCLI: `oxygen linkedin inbox backfill-status`.\n\nMCP: `oxygen_linkedin_inbox_backfill_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_inbox_backfill_status"],"x-oxygen-cli-command":"oxygen linkedin inbox backfill-status"},"post":{"operationId":"postLinkedinInboxBackfill","tags":["Linkedin"],"summary":"Backfill LinkedIn Message History","description":"Opt-in, LinkedIn only: pull a LinkedIn account's OLDER message history into the unibox as a slow durable background drip (one bounded page per thread per tick, default 10 reads/day) so long histories fill over days without burning account limits. NEW messages already arrive live via webhooks. conversation = one thread; account = one sender; omit both for every active LinkedIn account. Re-running re-arms the drip (backfilled threads never re-read); cancel=true stops it. A read: no messages sent, no credits charged.\n\nMCP: `oxygen_inbox_backfill`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender account (sender id, connection id, or Unipile account id). Omit for every active LinkedIn account."},"account_id":{},"chat_id":{},"conversation":{"type":"string","description":"Optional single conversation to backfill (conversation id or Unipile chat id). Scopes the sender's drip to just this thread."},"conversation_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_backfill"]}},"/api/cli/linkedin/inbox/backfill/cancel":{"post":{"operationId":"postLinkedinInboxBackfillCancel","tags":["Linkedin"],"summary":"Backfill LinkedIn Message History","description":"Opt-in, LinkedIn only: pull a LinkedIn account's OLDER message history into the unibox as a slow durable background drip (one bounded page per thread per tick, default 10 reads/day) so long histories fill over days without burning account limits. NEW messages already arrive live via webhooks. conversation = one thread; account = one sender; omit both for every active LinkedIn account. Re-running re-arms the drip (backfilled threads never re-read); cancel=true stops it. A read: no messages sent, no credits charged.\n\nMCP: `oxygen_inbox_backfill`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender account (sender id, connection id, or Unipile account id). Omit for every active LinkedIn account."},"account_id":{},"conversation":{"type":"string","description":"Optional single conversation to backfill (conversation id or Unipile chat id). Scopes the sender's drip to just this thread."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_inbox_backfill"]}},"/api/cli/linkedin/ingestion/status":{"get":{"operationId":"getLinkedinIngestionStatus","tags":["Linkedin"],"summary":"LinkedIn Ingestion Status","description":"One unified view of every 'read LinkedIn into the workspace' background drip — connections import, post-engagement harvest, and message-history backfill — across all connected accounts: each job's kind, status, items ingested, pages read, next slice time, and last error, PLUS each account's remaining ingest read budget for the day (relations / api / messages ingest reads vs. their dedicated caps) so a cap-deferred drip is explained. These drips trickle reads in slowly under dedicated conservative budgets so they never starve the sequencer's own reads. account scopes to one sender (sender id, connection id, or Unipile account id); omit for every account. Read-only.\n\nMCP: `oxygen_linkedin_ingestion_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Sender id, connection id, or Unipile account id."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_ingestion_status"]}},"/api/cli/linkedin/inmail-balance":{"get":{"operationId":"getLinkedinInmailBalance","tags":["Linkedin"],"summary":"LinkedIn InMail Credit Balance","description":"Reads the remaining LinkedIn InMail credit balance for a connected sender account (requires Premium / Sales Navigator / Recruiter on that account). Use before enrolling an InMail sequencer step so a campaign does not stall on an account with zero credits. account selects which sender to read (defaults to the org's primary LinkedIn account). Each LinkedIn service holds an independent credit pool: `inmail_balance` totals every subscribed pool unless service narrows it, and `response.credits` breaks it down per service. A sender can report is_premium=true and still hold 0 credits — Open Profile targets accept InMails for free regardless.\n\nMCP: `oxygen_inmail_balance`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Optional sender account id, connection id, or Unipile account id. Defaults to the org's primary connected LinkedIn account."}},{"name":"service","in":"query","required":false,"schema":{"type":"string","enum":["classic","sales_navigator","recruiter"],"description":"Optional LinkedIn service whose credit pool to read. Defaults to every subscribed service."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_inmail_balance"]}},"/api/cli/linkedin/intent":{"get":{"operationId":"getLinkedinIntent","tags":["Linkedin"],"summary":"LinkedIn Intent Status","description":"Shows the canonical linked people/touchpoint tables and the capture-only LinkedIn feeds filling them. Read-only.\n\nMCP: `oxygen_linkedin_intent_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_intent_status"]},"post":{"operationId":"postLinkedinIntent","tags":["Linkedin"],"summary":"Set Up LinkedIn Intent Tables","description":"Creates or reuses two durable OXYGEN Tables: one deduped LinkedIn Engaged People table and one linked LinkedIn Touchpoints table. Arms capture-only LinkedIn FEEDS on those tables (live tables that keep filling) for weekly profile viewers, new followers, and new connections; optionally one post's reactions + comments. Engagement stays out of CRM. Signup, inbound reply, meeting, or an explicit manual assert are the promotion gates.\n\nMCP: `oxygen_linkedin_intent_setup`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Connected LinkedIn sender to read through."},"account_id":{},"post":{"type":"string","description":"Optional composite social_id for a recurring post-engager watch."},"post_id":{},"post_url":{"type":"string","description":"Optional public URL for the watched post."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_intent_setup"]}},"/api/cli/linkedin/intent/autoenroll":{"post":{"operationId":"postLinkedinIntentAutoenroll","tags":["Linkedin"],"summary":"Arm LinkedIn Intent Auto-Enroll","description":"Binds the standing auto-enroll grant on LinkedIn intent captures: people a capture lands enroll into a Sequence each cycle, paced by the sender's warm-up ramp and the caps set here. PREVIEW BY DEFAULT — without approved=true nothing is written and the plan comes back. approved=true arms a STANDING grant: recurring outreach to people the user has not seen, with no further per-cycle approval until revoked. include_existing_network also enrolls the account's EXISTING connections — the entire standing network, not only people who arrive from now on. disable=true revokes the grant. Create the captures first with oxygen_linkedin_intent_setup.\n\nMCP: `oxygen_linkedin_intent_autoenroll`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Connected LinkedIn sender the captures read through."},"account_id":{},"approved":{"type":"boolean","description":"Set true to actually arm the standing grant. Omit/false returns the preview only."},"capture":{},"captures":{"type":"array","description":"Capture kinds to bind (connections, followers, profile_viewers, own_posts, post). Defaults to those oxygen_linkedin_intent_setup provisioned for this sender; naming a kind it never provisioned creates that capture.","items":{"type":"string"}},"disable":{"type":"boolean","description":"Revoke the standing grant instead of arming it. Needs no approval."},"include_existing_network":{"type":"boolean","description":"Also enroll the account's EXISTING connections/followers, not just people captured from now on."},"max_credits_per_cycle":{"type":"number","minimum":1,"description":"Hard credit ceiling for one enrollment cycle. Must be > 0; omit to inherit the plan-tier default."},"max_enrolls_per_day":{"type":"integer","minimum":1,"description":"People enrolled per day, within the sender's warm-up ramp. Must be > 0; omit to inherit the ramped daily cap. To enroll nobody use disable=true, not 0."},"post":{},"post_id":{"type":"string","description":"Composite social_id when binding the post-engager capture."},"post_url":{"type":"string","description":"Public URL of the watched post."},"sequence":{"type":"string","description":"Sequence id or slug the captured people are enrolled into. Required to arm and to preview."},"sequence_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_intent_autoenroll"]}},"/api/cli/linkedin/posts":{"get":{"operationId":"getLinkedinPosts","tags":["Linkedin"],"summary":"Get a LinkedIn Post","description":"Gets a LinkedIn post by id and returns its full record — crucially the composite social_id you must pass to oxygen_posts_comments_list / oxygen_posts_reactions_list / oxygen_engagement_list_engagers. post accepts a numeric activity id, an activity URL, or a social_id. account selects which sender account reads it (sender id, connection id, or Unipile account id); omit to use the org default.\n\nMCP: `oxygen_posts_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Optional sender account to read from (sender id, connection id, or Unipile account id). Omit to use the org default."}},{"name":"post","in":"query","required":false,"schema":{"type":"string","description":"Post id: numeric activity id, activity URL, or social_id."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_posts_get"]},"post":{"operationId":"postLinkedinPosts","tags":["Linkedin"],"summary":"Publish a LinkedIn Post","description":"Publishes a LinkedIn post from a connected sender account (or as a company with as_organization), with optional media, an external-link preview, mentions, a repost, or an embedded job. This is a REAL LinkedIn write that everyone can see and consumes the account's daily action quota: call once with approved=false (default) to preview exactly what will be posted, then again with approved=true to publish immediately outside the Publishing approval queue. For scheduled review and approval, use oxygen_publishing_posts_create, oxygen_publishing_posts_review and oxygen_publishing_posts_approve. account selects which sender account posts (sender id, connection id, or Unipile account id); omit it to use the org's default LinkedIn account.\n\nMCP: `oxygen_posts_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender account to post from (sender id, connection id, or Unipile account id). Omit to use the org default."},"approved":{"type":"boolean","description":"Set true to actually publish. Omit/false returns a preview only."},"as_organization":{"type":"string","description":"LinkedIn organization id to publish as a company page instead of the member."},"attachments":{"type":"array","maxItems":20,"items":{"type":"object","properties":{"content":{"type":"string"},"content_type":{"type":"string"},"filename":{"type":"string"}},"required":["content","content_type","filename"],"additionalProperties":false},"description":"Media as standard base64 with MIME type and safe filename."},"external_link":{"type":"string","description":"URL to attach as a link preview."},"include_job_posting":{"type":"string","description":"LinkedIn job id to embed as a job preview."},"mentions":{},"repost":{"type":"string","description":"LinkedIn post id to repost (quote/share)."},"text":{"type":"string","description":"Post body. To @-mention a person or company, put @<public-identifier> directly in the text (e.g. @tim-scheuer-91b005237, or @<company-public-id>) — Unipile resolves it to a tagged link. A bare display name does not tag.","minLength":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_posts_create"]},"delete":{"operationId":"deleteLinkedinPosts","tags":["Linkedin"],"summary":"Delete a LinkedIn Post","description":"Deletes a LinkedIn post the account authored — a real, irreversible LinkedIn write. post is the composite social_id returned by oxygen_posts_create (or oxygen_posts_get). Useful for cleaning up a mistaken post or a post→verify→delete test. account selects which sender account (sender id, connection id, or Unipile account id); omit to use the org default.\n\nMCP: `oxygen_posts_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Sender id, connection id, or Unipile account id. Omit to use the org default."}},{"name":"post","in":"query","required":false,"schema":{"type":"string","description":"Post social_id to delete (e.g. WyJ… — the id returned when the post was created)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_posts_delete"]}},"/api/cli/linkedin/posts/comments":{"get":{"operationId":"getLinkedinPostsComments","tags":["Linkedin"],"summary":"List LinkedIn Post Comments","description":"Lists comments on a LinkedIn post (or, with comment_id, the replies under one comment). IMPORTANT: post must be the composite social_id from oxygen_posts_get / users_posts — an activity URN is rejected (400 Invalid Post ID). Paged: 100 max per call — follow comments.cursor for the rest; a bigger limit does not return more. account picks the sender (default: org's).\n\nMCP: `oxygen_posts_comments_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Sender id, connection id, or Unipile account id."}},{"name":"comment_id","in":"query","required":false,"schema":{"type":"string","description":"List replies under this comment id instead of top-level comments."}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Pagination cursor from a previous response."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"Max comments to return."}},{"name":"post","in":"query","required":false,"schema":{"type":"string","description":"Composite social_id from oxygen_posts_get/users_posts (NOT the activity URN)."}},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","enum":["MOST_RECENT","TOP"],"description":"MOST_RECENT (default) or TOP."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_posts_comments_list"]}},"/api/cli/linkedin/posts/reactions":{"get":{"operationId":"getLinkedinPostsReactions","tags":["Linkedin"],"summary":"List LinkedIn Post Reactions","description":"Lists who reacted to a LinkedIn post (or, with comment_id, to one comment). IMPORTANT: post must be the composite social_id from oxygen_posts_get / users_posts — an activity URN is rejected (400 Invalid Post ID). Paged: 100 max per call — follow reactions.cursor for the rest; a bigger limit does not return more. account picks the sender (default: org's).\n\nMCP: `oxygen_posts_reactions_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Sender id, connection id, or Unipile account id."}},{"name":"comment_id","in":"query","required":false,"schema":{"type":"string","description":"List reactions on this comment id instead of the post."}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Pagination cursor from a previous response."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"Max reactions to return."}},{"name":"post","in":"query","required":false,"schema":{"type":"string","description":"Composite social_id from oxygen_posts_get/users_posts (NOT the activity URN)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_posts_reactions_list"]}},"/api/cli/linkedin/viewers":{"get":{"operationId":"linkedin.viewers.list","tags":["Linkedin"],"summary":"Who Viewed My LinkedIn Profile","description":"Read named LinkedIn profile viewers, respecting the connected account's privacy ceiling.\n\nCLI: `oxygen linkedin viewers list`.\n\nMCP: `oxygen_profile_viewers`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string"}},{"name":"start","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"include_raw","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_profile_viewers"],"x-oxygen-cli-command":"oxygen linkedin viewers list"}},"/api/cli/linkedin/viewers/enrichment":{"post":{"operationId":"postLinkedinViewersEnrichment","tags":["Linkedin"],"summary":"Professional Network Profile Viewers Enrichment","description":"Switches standing automatic full-profile enrichment of NEW profile viewers on or off (managed LinkedIn profile: about, current role and company, experience, education, location). This is STANDING credit spend: credits_per_person credits per enriched viewer, only for viewers first seen after enrichment.enabled_at, each delivery bounded by enrichment.max_credits_per_delivery (plan default) — never a one-off charge. Switching on adds the Person profile columns; existing rows are never charged by it (run that column on demand). enabled is required: true switches it on, false switches it off. oxygen_profile_viewers_import also accepts an optional enrich flag to set this in the same call.\n\nMCP: `oxygen_profile_viewers_enrichment`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"true switches standing enrichment on; false switches it off."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_profile_viewers_enrichment"]}},"/api/cli/linkedin/viewers/import":{"get":{"operationId":"getLinkedinViewersImport","tags":["Linkedin"],"summary":"Professional Network Profile Viewers Import Status","description":"Shows durable LinkedIn profile-viewers (WVMP) import progress: accounts[] lists every connected LinkedIn account with its display_name, headline, picture_url, per-account on (true when switched on) and state (off|collecting|waiting|paused|attention) with state_note, collected (distinct named viewers; job items_ingested counts re-sightings, so runs higher), last_read_at/next_read_at, and whether it is toggleable — plus a preview of the viewers table, enrichment (on, credits_per_person — see oxygen_profile_viewers_enrichment) and a deep-link to open it. Job/org health adds a paused value for an account switched off with oxygen_profile_viewers_pause; oxygen_profile_viewers_import resumes it. account scopes to one sender (sender id, connection id, or Unipile account id); omit for every sender's import. Read-only.\n\nMCP: `oxygen_profile_viewers_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_profile_viewers_status"]},"post":{"operationId":"postLinkedinViewersImport","tags":["Linkedin"],"summary":"Import Professional Network Profile Viewers","description":"Promotes 'who viewed my profile' (WVMP) from a one-shot read into a durable, deduped signal: reads named viewers into a Clay-like workspace table you can enrich and qualify, plus a deduped system-of-record mirror (view_count + last_viewed_at accumulate across walks). This starts a SLOW, durable background import that drips viewers in over many worker ticks under a dedicated conservative read budget — poll oxygen_profile_viewers_status to watch it accrue. LinkedIn only reveals viewers who browsed non-privately, so the table is always a partial sample (the preserved ceiling note explains the privacy limit). account selects which sender's WVMP to import (sender id, connection id, or Unipile account id); omit for every active LinkedIn account. table targets an existing workspace table (id or slug); omit to create/reuse a 'LinkedIn Profile Viewers' table. The import itself is a read: no messages are sent and no Oxygen credits are charged. enrich is opt-in STANDING paid enrichment of new viewers (see oxygen_profile_viewers_enrichment) — omit it to leave enrichment unchanged. (The synchronous one-shot read is still oxygen_profile_viewers.)\n\nMCP: `oxygen_profile_viewers_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender account to import (sender id, connection id, or Unipile account id). Omit to import every active LinkedIn account."},"enrich":{"type":"boolean","description":"Also switch standing full-profile enrichment on (true) or off (false) for new viewers. Omit to leave it unchanged."},"table":{"type":"string","description":"Optional existing workspace table (id or slug) to import into. Omit to create/reuse a 'LinkedIn Profile Viewers' table."},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_profile_viewers_import"]}},"/api/cli/linkedin/viewers/pause":{"post":{"operationId":"postLinkedinViewersPause","tags":["Linkedin"],"summary":"Pause Professional Network Profile Viewers Import","description":"Switches the profile-viewers (WVMP) import off for one account or all: rows and the table stay exactly as they are, and oxygen_profile_viewers_import switches it back on. account selects which sender to pause (sender id, connection id, or Unipile account id); omit to pause every account. An import landed by a LinkedIn capture feed is not touched here — pause that feed instead. Free; nothing is sent.\n\nMCP: `oxygen_profile_viewers_pause`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional account to pause (sender id, connection id, or Unipile account id). Omit to pause every account."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_profile_viewers_pause"]}},"/api/cli/linkedin/viewers/status":{"get":{"operationId":"getLinkedinViewersStatus","tags":["Linkedin"],"summary":"Professional Network Profile Viewers Import Status","description":"Shows durable LinkedIn profile-viewers (WVMP) import progress: accounts[] lists every connected LinkedIn account with its display_name, headline, picture_url, per-account on (true when switched on) and state (off|collecting|waiting|paused|attention) with state_note, collected (distinct named viewers; job items_ingested counts re-sightings, so runs higher), last_read_at/next_read_at, and whether it is toggleable — plus a preview of the viewers table, enrichment (on, credits_per_person — see oxygen_profile_viewers_enrichment) and a deep-link to open it. Job/org health adds a paused value for an account switched off with oxygen_profile_viewers_pause; oxygen_profile_viewers_import resumes it. account scopes to one sender (sender id, connection id, or Unipile account id); omit for every sender's import. Read-only.\n\nMCP: `oxygen_profile_viewers_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Sender id, connection id, or Unipile account id."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_profile_viewers_status"]}},"/api/cli/mailboxes":{"get":{"operationId":"getMailboxes","tags":["Mailboxes"],"summary":"List Sending Mailboxes","description":"Compact sender roster and totals (default). Full repair evidence and daily limits: oxygen_mailboxes_get.\n\nMCP: `oxygen_mailboxes_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"next_action","in":"query","required":false,"schema":{"type":"string"}},{"name":"stalled","in":"query","required":false,"schema":{"type":"boolean","description":"Enrolled, 0 sent."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","paused","disabled","provisioning"]}},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["summary","full"]}},{"name":"warmup","in":"query","required":false,"schema":{"type":"string","description":"Comma truth states."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_list"]},"post":{"operationId":"postMailboxes","tags":["Mailboxes"],"summary":"Import Sending Mailboxes","description":"Imports non-secret identities, inline or Zapmail. Every inbox lands under a sender profile; sender_profile_id names it, else names on the row find or create one. Receipts carry the OAuth review plan.\n\nMCP: `oxygen_mailboxes_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connection_id":{"type":"string","description":"Zapmail connection; omit for the default."},"mailboxes":{"type":"array","items":{"type":"object","description":"Mailbox identity; upserts by address.","properties":{"email_address":{"type":"string","description":"Sending address."},"provider":{"type":"string","enum":["google","microsoft"],"description":"google or microsoft."},"workspace_external_id":{"type":"string","description":"External provider ref."},"infrastructure_platform":{"type":"string","enum":["google_workspace","microsoft_365","microsoft_azure"],"description":"Actual hosting platform, separate from the export vendor."},"tenant_id":{"type":"string","description":"Optional Microsoft Entra tenant GUID."},"first_name":{"type":"string"},"last_name":{"type":"string"},"display_name":{"type":"string","description":"From name."},"sender_profile_id":{"type":"string","description":"This row's sender."}},"required":["email_address","provider"],"additionalProperties":false},"maxItems":500,"description":"Inline identities; omit for Zapmail."},"sender_profile_id":{"type":"string","description":"Sender for every row."},"service_provider":{"type":"string","enum":["google","microsoft"],"description":"Zapmail pool: google or microsoft."},"source":{"type":"string","enum":["inline","zapmail"],"description":"Identity source. Credentials use Accounts or CLI."},"source_provider":{"type":"string","minLength":1,"maxLength":64,"description":"Inline export-vendor provenance."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_import"]}},"/api/cli/mailboxes/{id}":{"get":{"operationId":"getMailboxesId","tags":["Mailboxes"],"summary":"Get One Sending Mailbox","description":"Gets one sender with connectionRepair/warmupRepair ownership; effective_cap is today's campaign limit and ramp-up. Fresh approved Google/Microsoft/Azure managed orders activate warmup automatically after provisioning: no mailbox credentials or standalone approval.\n\nMCP: `oxygen_mailboxes_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_get"]},"patch":{"operationId":"patchMailboxesId","tags":["Mailboxes"],"summary":"Update Mailbox Profile","description":"Update a mailbox’s display name, signature, bounce protection or AI classification scope. No credits.\n\nMCP: `oxygen_mailboxes_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"bounce_protection":{"type":"object","additionalProperties":true,"description":"Partial merge; defaults enabled=true, warning_rate=.02, pause_rate=.03, min_sends=20, window_days=7. Rolling hard bounces/accepted sends; pauses this mailbox. Sequence policy is separate."},"classification_scope":{"type":"string","enum":["replies","all"],"description":"replies: only Sequence threads and threads you wrote in; all: every inbound conversation. Credits each."},"display_name":{"type":"string","description":"From display name. Empty string clears it."},"signature_html":{"type":"string","description":"HTML signature added to each send that lacks it. Empty string clears it."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_update"]}},"/api/cli/mailboxes/{id}/cap":{"patch":{"operationId":"patchMailboxesIdCap","tags":["Mailboxes"],"summary":"Set Mailbox Daily Cap","description":"Sets a mailbox's campaign cap: standard default 25, Entra maximum 2/day; oxygen_limits_show reports limits. Ramps may lower it. Free write.\n\nMCP: `oxygen_mailboxes_set_cap`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"daily_cap":{"type":"number","description":"Sends/day; positive integer."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_set_cap"]}},"/api/cli/mailboxes/{id}/ramp":{"patch":{"operationId":"patchMailboxesIdRamp","tags":["Mailboxes"],"summary":"Set Mailbox Campaign Ramp","description":"Sets the campaign ramp-up: start_per_day, then +step every increase_every_days sending days until the daily cap. off:true uses the configured cap; Entra stays at most 2/day. clear:true restores 5/10/20. Returns effective_cap. Free write.\n\nMCP: `oxygen_mailboxes_set_ramp`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ramp_config":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_set_ramp"]}},"/api/cli/mailboxes/{id}/sequences":{"get":{"operationId":"mailboxes.sequences","tags":["Mailboxes"],"summary":"Mailboxes sequences","description":"Read the sequences using one sending mailbox by id or email address.\n\nCLI: `oxygen mailboxes sequences`.\n\nMCP: `oxygen_mailbox_sequences`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailbox_sequences"],"x-oxygen-cli-command":"oxygen mailboxes sequences"}},"/api/cli/mailboxes/{id}/standby":{"get":{"operationId":"mailboxes.standby.get","tags":["Mailboxes"],"summary":"Mailboxes standby get","description":"Read a mailbox's standby role, readiness blockers and replacements.\n\nCLI: `oxygen mailboxes standby get`.\n\nMCP: `oxygen_mailboxes_standby_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_standby_get"],"x-oxygen-cli-command":"oxygen mailboxes standby get"},"patch":{"operationId":"mailboxes.standby.set","tags":["Mailboxes"],"summary":"Mailboxes standby set","description":"Set outreach or standby. Preview; apply with approved and returned plan. Standby holds pending outreach; existing warm-up continues. 0 credits.\n\nCLI: `oxygen mailboxes standby set`.\n\nMCP: `oxygen_mailboxes_standby_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["outreach","standby"]},"approved":{"type":"boolean"},"plan":{"type":"string"}},"required":["role"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_standby_set"],"x-oxygen-cli-command":"oxygen mailboxes standby set"}},"/api/cli/mailboxes/{id}/status":{"post":{"operationId":"postMailboxesIdStatus","tags":["Mailboxes"],"summary":"Set Mailbox Status","description":"Sets a sending mailbox's status. Pausing or disabling takes the inbox out of the rotation pool (the worker stops sending through it) without removing it or losing its warmup state; active returns it to rotation.\n\nMCP: `oxygen_mailboxes_set_status`, `oxygen_mailboxes_warmup_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mailboxes":{},"status":{"type":"string","enum":["active","paused","disabled"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_set_status","oxygen_mailboxes_warmup_action"]}},"/api/cli/mailboxes/{id}/tags":{"post":{"operationId":"postMailboxesIdTags","tags":["Mailboxes"],"summary":"Tag Mailbox","description":"Replaces a sending mailbox's workspace tags (Tags primitive; see oxygen_tags_list). Whole-set: pass the full list, [] clears. Pools identities under a campaign tag.\n\nMCP: `oxygen_mailboxes_tag`, `oxygen_mailboxes_warmup_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mailboxes":{},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"The full workspace tag list to set ([] clears)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_tag","oxygen_mailboxes_warmup_action"]}},"/api/cli/mailboxes/{id}/warmup-config":{"patch":{"operationId":"patchMailboxesIdWarmupConfig","tags":["Mailboxes"],"summary":"Set Mailbox Warmup Settings","description":"Provider warm-up settings, separate from the campaign ramp. Standard 1/day, +1/day, max 10/day; dedicated tenants stay stricter. All four knobs or clear:true for defaults. Active sync is free; provider_sync reports the result.\n\nMCP: `oxygen_mailboxes_warmup_config`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"warmup_config":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_config"]}},"/api/cli/mailboxes/compatibility":{"get":{"operationId":"getMailboxesCompatibility","tags":["Mailboxes"],"summary":"Mailbox Provider Compatibility","description":"Read-only mailbox origin/auth verdicts. Filters/summary_only narrow rows; catalog_only returns the import contract. No decryption/writes; InboxKit may read source-warmup status.\n\nMCP: `oxygen_mailboxes_compatibility`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"catalog_only","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"mailboxes","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"provider","in":"query","required":false,"schema":{"type":"string","enum":["google","microsoft"]}},{"name":"remedy","in":"query","required":false,"schema":{"type":"string","description":"oauth skips provider reads."}},{"name":"summary_only","in":"query","required":false,"schema":{"type":"boolean","description":"Counts without mailbox rows."}},{"name":"vendor","in":"query","required":false,"schema":{"type":"string","description":"Canonical mailbox origin filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_compatibility"]}},"/api/cli/mailboxes/connect-oauth":{"get":{"operationId":"getMailboxesConnectOauth","tags":["Mailboxes"],"summary":"Mail Connection Status","description":"Read consent/history progress by OAuth run id. Connected requires verified mailbox identity/scopes.\n\nMCP: `oxygen_mailboxes_connect_oauth_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","description":"zapmail connection."}},{"name":"export_id","in":"query","required":false,"schema":{"type":"string","description":"OAuth run id."}},{"name":"vendor","in":"query","required":false,"schema":{"type":"string","enum":["zapmail","inboxkit","oxygen","composio"],"description":"Path override."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_connect_oauth_status"]},"post":{"operationId":"postMailboxesConnectOauth","tags":["Mailboxes"],"summary":"Connect Mailboxes","description":"Composio: max 10 exact registered addresses; 100 credits/mailbox/month for Inbox/Sent/archive sync and CRM (no spam/trash/drafts). Price/first debit: oxygen_billing_commitments view=connection-prices. oxygen: Microsoft tenant max 500, provider-wide unless Exchange RBAC. Ordinary/Google: individual; google_smtp adds SMTP. No source credentials. InboxKit: 0-credit eligibility/domain-approval preview; approve plan_hash.\n\nMCP: `oxygen_mailboxes_connect_oauth`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"authorization_mode":{"type":"string","enum":["auto","tenant","individual"],"description":"oxygen: tenant is Microsoft-only."},"canary":{"type":"boolean","description":"InboxKit: false fans out."},"connection_id":{"type":"string","description":"zapmail connection."},"domains":{"type":"array","items":{"type":"string"},"description":"InboxKit domains."},"dry_run":{"type":"boolean"},"google_smtp":{"type":"boolean","description":"Google SMTP OAuth (oxygen only)."},"mailboxes":{"type":"array","items":{"type":"string"},"description":"Exact addresses."},"plan_hash":{"type":"string","description":"InboxKit reviewed hash."},"provider":{"type":"string","enum":["google","microsoft"]},"vendor":{"type":"string","enum":["zapmail","inboxkit","oxygen","composio"],"description":"composio: owned mail; default zapmail."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_connect_oauth"]}},"/api/cli/mailboxes/delegation":{"get":{"operationId":"getMailboxesDelegation","tags":["Mailboxes"],"summary":"Mailbox Delegation Status","description":"Google sending-domain delegation only, not Microsoft OAuth or a credential-file handoff to OXYGEN Warm-up/OXYGEN deliverability. Reports coverage and required client id/scopes; probe=true mints one token per mailbox. Read-only; sends no mail; 0 credits.\n\nMCP: `oxygen_mailboxes_delegation_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"query","required":false,"schema":{"type":"string","description":"Only report this sending domain."}},{"name":"probe","in":"query","required":false,"schema":{"type":"boolean","description":"Mint one delegated token per mailbox."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_delegation_status"]}},"/api/cli/mailboxes/delete":{"post":{"operationId":"postMailboxesDelete","tags":["Mailboxes"],"summary":"Delete Mailboxes","description":"Preview/approve deleting exact mailboxes, or whole domains with all their inboxes, at 0 credits; no refund. Keeps history and provider accounts. Listed sequences keep status but lose these senders. OXYGEN domains are cancelled (bought-alone ones stop renewing), your own archived. Pass the same args on preview and approval.\n\nMCP: `oxygen_mailboxes_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"cascade":{"type":"boolean","description":"Also disconnect each mailbox's own warm-up and monitoring instead of failing closed."},"confirmation":{"type":"string"},"domains":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500},"include_domains":{"type":"boolean","description":"Also delete domains whose inboxes are all selected."},"mailboxes":{"type":"array","items":{"type":"string"},"maxItems":500,"description":"Exact ids or addresses."},"planHash":{},"plan_hash":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_delete"]}},"/api/cli/mailboxes/emailguard":{"post":{"operationId":"postMailboxesEmailguard","tags":["Mailboxes"],"summary":"Connect OXYGEN deliverability","description":"Preview every mailbox origin and approve OXYGEN deliverability monitoring for credential-capable Google Workspace mailboxes (managed, Zapmail, or a compatible encrypted external import). Identity-only/manual/native Google reports credential_required. Approval echoes plan_hash/max_credits. Managed: 100 credits/mailbox-month; BYOK: 0. Microsoft 365/Azure is vendor-blocked: OXYGEN deliverability has no Microsoft OAuth or tenant-consent handoff; never password auth. Passwords and seed sends are excluded from responses.\n\nMCP: `oxygen_mailboxes_deliverability_connect`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Run the previewed write."},"mailboxes":{"type":"array","items":{"type":"string"},"description":"Mailbox ids/addresses; omit for all."},"max_credits":{"type":"number","minimum":0,"description":"First-cycle cap; 0 for BYOK."},"planHash":{},"plan_hash":{"type":"string","description":"Fresh preview hash."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_connect"]}},"/api/cli/mailboxes/emailguard/auto-enroll":{"get":{"operationId":"mailboxes.emailguard.auto_enroll.get","tags":["Mailboxes"],"summary":"Mailboxes deliverability auto enroll","description":"Read the workspace's automatic monitoring enrollment grant and last sweep.\n\nMCP: `oxygen_mailboxes_deliverability_auto_enroll_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_auto_enroll_get"]},"post":{"operationId":"mailboxes.emailguard.auto_enroll.set","tags":["Mailboxes"],"summary":"Mailboxes deliverability auto enroll","description":"Preview, arm or disarm automatic mailbox monitoring. Arming recurring spend requires approved=true and max_credits_per_cycle.\n\nMCP: `oxygen_mailboxes_deliverability_auto_enroll_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"approved":{"type":"boolean"},"max_credits_per_cycle":{"type":"number","minimum":0},"run":{"type":"boolean"},"dry_run":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_auto_enroll_set"]}},"/api/cli/mailboxes/emailguard/disconnect":{"post":{"operationId":"postMailboxesEmailguardDisconnect","tags":["Mailboxes"],"summary":"Disconnect OXYGEN deliverability","description":"Preview/approve owned OXYGEN deliverability account deletion with plan_hash. Billing stops only after confirmed remote deletion.\n\nMCP: `oxygen_mailboxes_deliverability_disconnect`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Run the previewed deletion."},"mailboxes":{"type":"array","items":{"type":"string"},"description":"Mailbox ids/addresses; omit for all."},"planHash":{},"plan_hash":{"type":"string","description":"Fresh preview hash."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_deliverability_disconnect"]}},"/api/cli/mailboxes/google-workspace/connect":{"post":{"operationId":"postMailboxesGoogleWorkspaceConnect","tags":["Mailboxes"],"summary":"Connect Google Workspace Admin","description":"Preview admin scopes for Gmail logs, domain/account management and Postmaster. approved=true creates a Google administrator consent link. No mailbox grant or paid enrollment.\n\nMCP: `oxygen_mailboxes_google_workspace_connect`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"dry_run":{"type":"boolean"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_google_workspace_connect"]}},"/api/cli/mailboxes/google-workspace/disconnect":{"post":{"operationId":"postMailboxesGoogleWorkspaceDisconnect","tags":["Mailboxes"],"summary":"Disconnect Google Workspace Admin","description":"Remove this stored admin credential with approved=true; preserve mailbox grants.\n\nMCP: `oxygen_mailboxes_google_workspace_disconnect`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"connection_id":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_google_workspace_disconnect"]}},"/api/cli/mailboxes/google-workspace/status":{"get":{"operationId":"getMailboxesGoogleWorkspaceStatus","tags":["Mailboxes"],"summary":"Google Workspace Access","description":"Inspect admin grants; live=true probes Google read access, including Gmail logs. No sends, settings changes or spend.\n\nMCP: `oxygen_mailboxes_google_workspace_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_google_workspace_status"]}},"/api/cli/mailboxes/health":{"get":{"operationId":"getMailboxesHealth","tags":["Mailboxes"],"summary":"Email Fleet Health","description":"Fleet health: health_coverage, warmup.byCause, domains. 0 credits; advisory.\n\nMCP: `oxygen_mailboxes_health`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_health"]}},"/api/cli/mailboxes/oauth-health":{"get":{"operationId":"getMailboxesOauthHealth","tags":["Mailboxes"],"summary":"Mailbox OAuth Health","description":"Rolls up every Google/Microsoft sending mailbox with no usable individual OAuth or verified delegation/application access, minus Google domains already covered by delegation. Imported/manual rows use remedy=connect_oauth_oxygen; Microsoft can use exact-scope tenant authorization or individual OAuth. InboxKit uses connect_oauth_inboxkit. Read-only, 0 credits.\n\nMCP: `oxygen_mailboxes_oauth_health`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_oauth_health"]}},"/api/cli/mailboxes/standby":{"get":{"operationId":"mailboxes.standby.pool","tags":["Mailboxes"],"summary":"Mailboxes standby pool","description":"Read shared warm standby reserve, readiness policy and replacements.\n\nCLI: `oxygen mailboxes standby pool`.\n\nMCP: `oxygen_mailboxes_standby_pool`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_standby_pool"],"x-oxygen-cli-command":"oxygen mailboxes standby pool"},"patch":{"operationId":"mailboxes.standby.policy","tags":["Mailboxes"],"summary":"Mailboxes standby policy","description":"Set required confirmed warm-up sending days (default 14); no subscription changes. 0 credits.\n\nCLI: `oxygen mailboxes standby policy`.\n\nMCP: `oxygen_mailboxes_standby_policy`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"minimum_days":{"type":"integer","minimum":1,"maximum":28}},"required":["minimum_days"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_standby_policy"],"x-oxygen-cli-command":"oxygen mailboxes standby policy"}},"/api/cli/mailboxes/sync":{"get":{"operationId":"getMailboxesSync","tags":["Mailboxes"],"summary":"Mail Sync Status","description":"Read mail history/CRM analysis progress.\n\nMCP: `oxygen_mailboxes_sync_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"mailbox","in":"query","required":false,"schema":{"type":"string","description":"Mailbox id/address."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_sync_status"]},"post":{"operationId":"postMailboxesSync","tags":["Mailboxes"],"summary":"Mail Sync","description":"Progress: oxygen_mailboxes_sync_status. Preview/approve controls. Disconnect stops sync/sends and mailbox renewals; mail/CRM stays. Seat/add-on contracts remain.\n\nMCP: `oxygen_mailboxes_sync`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["start","pause","resume","disconnect"]},"approved":{"type":"boolean"},"dry_run":{"type":"boolean"},"mailbox":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_sync"]}},"/api/cli/mailboxes/warmup":{"post":{"operationId":"postMailboxesWarmup","tags":["Mailboxes"],"summary":"Enable Mailbox Warmup","description":"STANDALONE path: OXYGEN Warm-up. InboxKit Google/Microsoft/Azure orders with warmup_activation.automatic_after_provisioning=true activate automatically: no customer-supplied mailbox credentials or second approval. InboxKit Google uses a just-in-time managed credential handoff; Microsoft/Azure uses native export. Managed Gmail reuses Composio after standard mailbox access approval (send/read/organize); no extra Google consent. 100 credits per warming-inbox-month; 0 once included in the mailbox connection. Preview costs 0 credits; dry_run calls no provider at all. Approve plan_hash/max_credits. Legacy Google: oxygen_mailboxes_warmup_google; Microsoft: oxygen_mailboxes_warmup_microsoft.\n\nMCP: `oxygen_mailboxes_warmup_enable`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"False previews at 0 credits; true runs the approved enrollment."},"billing_mode":{"type":"string","enum":["managed"],"description":"Managed; omit for automatic."},"connection_id":{"type":"string","description":"Legacy override; omit."},"dry_run":{"type":"boolean","description":"Call no provider."},"mailboxes":{"type":"array","items":{"type":"string"},"description":"Mailbox ids/addresses; omit for all."},"max_credits":{"type":"number","minimum":0,"description":"First-cycle credit cap."},"planHash":{},"plan_hash":{"type":"string","description":"Fresh preview hash."},"provider":{"type":"string","enum":["oxygen_warmup"],"description":"OXYGEN Warm-up; omit for automatic."},"ramp_weeks":{"type":"number","description":"Climb weeks (default 4); then 10/day."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_enable"]}},"/api/cli/mailboxes/warmup-profile":{"get":{"operationId":"mailboxes.warmup_profiles.get","tags":["Mailboxes"],"summary":"Mailboxes warmup profile","description":"Read available OXYGEN Warm-up profiles and current bindings.\n\nMCP: `oxygen_mailboxes_warmup_profiles`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_profiles"]},"post":{"operationId":"mailboxes.warmup_profiles.set","tags":["Mailboxes"],"summary":"Mailboxes warmup profile","description":"Preview or apply an OXYGEN Warm-up profile to exact mailboxes or domains; approved=true applies the reviewed scope.\n\nMCP: `oxygen_mailboxes_warmup_profile_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"profile":{"oneOf":[{"type":"string"},{"type":"object","additionalProperties":true},{"type":"null"}]},"budget":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"domains":{"type":"array","items":{"type":"string"}},"mailboxes":{"type":"array","items":{"type":"string"}},"all":{"type":"boolean"},"approved":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_profile_set"]}},"/api/cli/mailboxes/warmup/disable":{"post":{"operationId":"postMailboxesWarmupDisable","tags":["Mailboxes"],"summary":"Warmup Pause/Resume/Disable","description":"Uses each inbox's recorded rail: OXYGEN Warm-up, or TrulyInbox for older rows. pause/resume: 0 credits, no preview, subscription unchanged. disable removes/cancels billing. reconnect uses the current credential at 0 credits. reactivate rechecks OAuth, restarts a provider-stopped warm-up, no rebill; verify sends. Never disable+enable to repair: it rebills.\n\nMCP: `oxygen_mailboxes_warmup_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mailboxes":{"type":"array","items":{"type":"string"},"description":"Mailbox ids or addresses. Omit for the whole pool."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_action"]}},"/api/cli/mailboxes/warmup/google":{"post":{"operationId":"postMailboxesWarmupGoogle","tags":["Mailboxes"],"summary":"Authorize Google Warmup","description":"Legacy Google owner consent for 1–10 connected inboxes; managed Gmail uses warmup_enable. Preview, approve plan_hash/max_credits=0, open each consent_url as its exact inbox, poll status. No grants/passwords transfer. Google shows the provider's app. Warmup stays off; enable it separately.\n\nMCP: `oxygen_mailboxes_warmup_action`, `oxygen_mailboxes_warmup_google`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"mailboxes":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10,"description":"Exact ids or addresses."},"max_credits":{"type":"number","minimum":0,"maximum":0},"plan_hash":{"type":"string"},"status":{"type":"boolean"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_action","oxygen_mailboxes_warmup_google"]}},"/api/cli/mailboxes/warmup/microsoft":{"post":{"operationId":"postMailboxesWarmupMicrosoft","tags":["Mailboxes"],"summary":"Microsoft Warmup Consent","description":"NON-INBOXKIT FALLBACK ONLY. A fresh approved managed InboxKit Google/Microsoft/Azure order activates automatically; none needs customer-supplied Outlook consent or mailbox credentials. Legacy automatic scope repair is Microsoft/Azure-only. This fallback has NO tenant-wide admin consent: it returns ONE consent URL PER MAILBOX and a human must open each in a browser. Preview reports consent_urls_required and mints nothing; approve plan_hash with max_credits=0, then poll. Warmup stays off until standalone enable.\n\nMCP: `oxygen_mailboxes_warmup_action`, `oxygen_mailboxes_warmup_microsoft`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"mailboxes":{"type":"array","items":{"type":"string"},"description":"Fallback Microsoft ids/addresses; omit for pool."},"max_credits":{"type":"number","minimum":0,"maximum":0},"plan_hash":{"type":"string"},"status":{"type":"boolean"},"tenant_id":{"type":"string","description":"Ignored."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_action","oxygen_mailboxes_warmup_microsoft"]}},"/api/cli/mailboxes/warmup/pause":{"post":{"operationId":"postMailboxesWarmupPause","tags":["Mailboxes"],"summary":"Warmup Pause/Resume/Disable","description":"Uses each inbox's recorded rail: OXYGEN Warm-up, or TrulyInbox for older rows. pause/resume: 0 credits, no preview, subscription unchanged. disable removes/cancels billing. reconnect uses the current credential at 0 credits. reactivate rechecks OAuth, restarts a provider-stopped warm-up, no rebill; verify sends. Never disable+enable to repair: it rebills.\n\nMCP: `oxygen_mailboxes_warmup_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mailboxes":{"type":"array","items":{"type":"string"},"description":"Mailbox ids or addresses. Omit for the whole pool."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_action"]}},"/api/cli/mailboxes/warmup/reactivate":{"post":{"operationId":"postMailboxesWarmupReactivate","tags":["Mailboxes"],"summary":"Warmup Pause/Resume/Disable","description":"Uses each inbox's recorded rail: OXYGEN Warm-up, or TrulyInbox for older rows. pause/resume: 0 credits, no preview, subscription unchanged. disable removes/cancels billing. reconnect uses the current credential at 0 credits. reactivate rechecks OAuth, restarts a provider-stopped warm-up, no rebill; verify sends. Never disable+enable to repair: it rebills.\n\nMCP: `oxygen_mailboxes_warmup_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mailboxes":{"type":"array","items":{"type":"string"},"description":"Mailbox ids or addresses. Omit for the whole pool."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_action"]}},"/api/cli/mailboxes/warmup/reconnect":{"post":{"operationId":"postMailboxesWarmupReconnect","tags":["Mailboxes"],"summary":"Warmup Pause/Resume/Disable","description":"Uses each inbox's recorded rail: OXYGEN Warm-up, or TrulyInbox for older rows. pause/resume: 0 credits, no preview, subscription unchanged. disable removes/cancels billing. reconnect uses the current credential at 0 credits. reactivate rechecks OAuth, restarts a provider-stopped warm-up, no rebill; verify sends. Never disable+enable to repair: it rebills.\n\nMCP: `oxygen_mailboxes_warmup_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mailboxes":{"type":"array","items":{"type":"string"},"description":"Mailbox ids or addresses. Omit for the whole pool."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_action"]}},"/api/cli/mailboxes/warmup/resume":{"post":{"operationId":"postMailboxesWarmupResume","tags":["Mailboxes"],"summary":"Warmup Pause/Resume/Disable","description":"Uses each inbox's recorded rail: OXYGEN Warm-up, or TrulyInbox for older rows. pause/resume: 0 credits, no preview, subscription unchanged. disable removes/cancels billing. reconnect uses the current credential at 0 credits. reactivate rechecks OAuth, restarts a provider-stopped warm-up, no rebill; verify sends. Never disable+enable to repair: it rebills.\n\nMCP: `oxygen_mailboxes_warmup_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mailboxes":{"type":"array","items":{"type":"string"},"description":"Mailbox ids or addresses. Omit for the whole pool."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_action"]}},"/api/cli/mailboxes/warmup/status":{"get":{"operationId":"getMailboxesWarmupStatus","tags":["Mailboxes"],"summary":"Sync Mailbox Warmup","description":"Syncs and persists warmup at 0 credits; conditionally auto-pauses runaways on fresh evidence. Never enrolls/resumes; retired rows are never retargeted. Omit mailboxes for pool; dry_run skips providers but persists state.\n\nMCP: `oxygen_mailboxes_warmup_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"billing_mode","in":"query","required":false,"schema":{"type":"string","enum":["managed"],"description":"Managed; omit for automatic."}},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","description":"Legacy override; omit."}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"Skip the provider call (mailboxes marked pending)."}},{"name":"mailboxes","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Mailbox ids or addresses to sync. Omit to sync the whole pool."}},{"name":"provider","in":"query","required":false,"schema":{"type":"string","enum":["oxygen_warmup","trulyinbox"],"description":"Optional rail filter. Omit to read each mailbox from its recorded rail."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_mailboxes_warmup_status"]}},"/api/cli/managed-inboxes":{"get":{"operationId":"getManagedInboxes","tags":["Managed inboxes"],"summary":"List Managed Inboxes","description":"Lists subscriptions and orders. Quote order totals because subscription lines omit add-ons; only `warmup_activation.automatic_after_provisioning=true` on a preview or receipt is authoritative. InboxKit warmup needs no customer-supplied mailbox password or OAuth step. Native sending is a separate destination-bound OAuth contract, verified for each exact mailbox after provisioning; an existing token for another mailbox proves nothing. Optional status filter; read-only, 0 credits.\n\nMCP: `oxygen_managed_inboxes_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","active","renewing","past_due","expired","cancelled","failed"],"description":"Optional lifecycle status filter."}},{"name":"view","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_managed_inboxes_list"]}},"/api/cli/managed-inboxes/{domain}":{"get":{"operationId":"getManagedInboxesDomain","tags":["Managed inboxes"],"summary":"Get Managed Inbox","description":"Gets one managed subscription; poll until active; only `warmup_activation.automatic_after_provisioning=true` on a preview or receipt is authoritative. InboxKit warmup needs no customer-supplied mailbox password or OAuth step. Native sending is a separate destination-bound OAuth contract, verified for each exact mailbox after provisioning; an existing token for another mailbox proves nothing. Read-only, 0 credits.\n\nMCP: `oxygen_managed_inboxes_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_managed_inboxes_get"]}},"/api/cli/managed-inboxes/{domain}/mailboxes":{"post":{"operationId":"postManagedInboxesDomainMailboxes","tags":["Managed inboxes"],"summary":"Add Managed Inboxes to an Owned Domain","description":"Adds inboxes to an owned domain. NO domain registration is charged; one_off_credits=0. Preview: `mailboxes`, `senders`, `addons_monthly_credits`, caps, `warmup_activation` and quote_id. Approve quote_id, then poll oxygen_managed_inboxes_get. `avatar_durable=false` withholds the photo; inboxes ship permanently faceless. Warmup requires warmup_activation.automatic_after_provisioning=true; selection alone grants nothing. scope=warmup_only; Google transport=inboxkit_managed_google_handoff, Microsoft/Azure transport=inboxkit_sequencer_export; mailbox_credentials_required=false, native_send_oauth_separate=true. Warmup needs no supplied password/OAuth or second approval. Verify sending authorization for each exact new mailbox; another mailbox's token proves nothing. Unavailable warmup costs 0, warmup_activation=null; approve that fresh quote to buy without it. Caps include existing: 5 Google/Microsoft, 100 Azure.\n\nMCP: `oxygen_managed_inboxes_add_mailboxes`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required true (with quote_id) to place the expansion and authorize only enabled AND available standing add-ons for the exact new mailboxes; otherwise returns a priced preview."},"mailboxes":{"type":"array","items":{"type":"object","description":"sender_profile_id: name/photo (typed fields ignored, not an error), or first_name + last_name. Stamped PERMANENTLY.","properties":{"username":{"type":"string","description":"Use natural variants of the real sender (phil, p.hirte); avoid numbers unless explicitly requested."},"sender_profile_id":{"type":"string","description":"The sender owning this address (oxygen_senders_profiles_list). Several may share one."},"first_name":{"type":"string"},"last_name":{"type":"string"},"profile_picture_url":{"type":"string","description":"Optional avatar: a public, PERMANENT https URL."}},"required":["username"],"additionalProperties":false},"minItems":1,"description":"Mailboxes to ADD. The platform cap counts the inboxes already on the domain, so this is the increment, not the new total."},"max_mailboxes_per_domain":{"type":"integer","minimum":1,"maximum":100,"description":"Raises or lowers the saved per-domain limit, from current occupancy to the platform cap. Send on preview and approval."},"quote_id":{"type":"string","description":"The quote_id from a fresh preview. Required when approved=true."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_managed_inboxes_add_mailboxes"]}},"/api/cli/managed-inboxes/avatars":{"post":{"operationId":"managed_inboxes.avatars.prepare","tags":["Managed inboxes"],"summary":"Managed inboxes avatars prepare","description":"Prepare a scoped mailbox profile-picture upload; confirm the stored bytes before using its URL.\n\nCLI: `oxygen managed-inboxes avatars prepare`.\n\nMCP: `oxygen_managed_inbox_avatar_prepare`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content_type":{"type":"string","enum":["image/png","image/jpeg","image/webp"]},"content_length":{"type":"integer","minimum":1}},"required":["content_length"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_managed_inbox_avatar_prepare"],"x-oxygen-cli-command":"oxygen managed-inboxes avatars prepare"},"patch":{"operationId":"managed_inboxes.avatars.confirm","tags":["Managed inboxes"],"summary":"Managed inboxes avatars confirm","description":"Verify and normalize a mailbox profile picture owned by this workspace.\n\nCLI: `oxygen managed-inboxes avatars confirm`.\n\nMCP: `oxygen_managed_inbox_avatar_confirm`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"storage_key":{"type":"string"}},"required":["storage_key"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_managed_inbox_avatar_confirm"],"x-oxygen-cli-command":"oxygen managed-inboxes avatars confirm"}},"/api/cli/managed-inboxes/cancel":{"post":{"operationId":"postManagedInboxesCancel","tags":["Managed inboxes"],"summary":"Cancel Managed Inbox","description":"Cancel inboxes and all recurring warm-up/placement add-ons. Without approved=true, free itemized teardown shows monthly costs/freed credits, access_until (sending ends then) and live sequences_at_risk. Show before approval; require user's exact confirm_domain, never fill confirm_domain in yourself. Once canceled, preview original-address recovery eligibility with oxygen_managed_inboxes_recover. Domain registration lasts until term end.\n\nMCP: `oxygen_managed_inboxes_cancel`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required true to actually cancel; otherwise the teardown preview is returned."},"confirm_domain":{"type":"string","description":"Confirmation echo — must equal `domain`. Required with approved=true. Set only after the user has seen the preview and confirmed this domain."},"domain":{"type":"string","description":"The managed inbox domain to cancel (e.g. send.acme.com)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_managed_inboxes_cancel"]}},"/api/cli/managed-inboxes/domains/search":{"post":{"operationId":"managed_inboxes.domains.search","tags":["Managed inboxes"],"summary":"Managed inboxes search domains","description":"Search available domains for managed mailboxes; buys nothing.\n\nCLI: `oxygen managed-inboxes search-domains`.\n\nMCP: `oxygen_managed_inbox_domains_search`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"keyword":{"type":"string"},"tlds":{"type":"array","items":{"type":"string"}},"limit":{"type":"integer","minimum":1}},"required":["keyword"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_managed_inbox_domains_search"],"x-oxygen-cli-command":"oxygen managed-inboxes search-domains"}},"/api/cli/managed-inboxes/exit":{"post":{"operationId":"postManagedInboxesExit","tags":["Managed inboxes"],"summary":"Exit Managed Inbox","description":"Stops every OXYGEN renewal for a managed domain (inboxes, warm-up, placement) after the paid period and records a handoff request. NOT a cancel: domain, mailboxes, DNS, warm-up and data stay. Without approved=true returns the plan (`lines`, `keeps`, `vendor_carry_note`: OXYGEN pays the vendor past `access_until` until the human handoff or a cancel) — show it to the user. Execute with approved=true AND confirm_domain = the exact domain; never fill confirm_domain in yourself. The Google Workspace / registrar handoff is human-only. revoke=true resumes renewals. Idempotent. 0 credits.\n\nMCP: `oxygen_managed_inboxes_exit`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"true to execute; omit for the plan."},"confirm_domain":{"type":"string","description":"Must equal `domain`; required with approved=true and set only after the user confirmed it."},"contact":{"type":"string","description":"Handoff contact."},"domain":{"type":"string","description":"The managed domain to stop renewing."},"note":{"type":"string","description":"Handoff context (destination)."},"revoke":{"type":"boolean","description":"Undo a recorded exit so renewals resume."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_managed_inboxes_exit"]}},"/api/cli/managed-inboxes/recover":{"post":{"operationId":"postManagedInboxesRecover","tags":["Managed inboxes"],"summary":"Recover Managed Inboxes","description":"Restore canceled inboxes, or adopt ones the provider revived on a failed order: 0-credit eligibility, upfront and recurring quote. Verify authorization and warmup after.\n\nMCP: `oxygen_managed_inboxes_recover`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"True after human approval of the exact quote. Omit for a free read-only preview."},"domain":{"type":"string","description":"Managed domain."},"max_credits":{"type":"number","description":"Upfront credit ceiling required with approval; excludes recurring charges."},"quote_id":{"type":"string","description":"Fresh preview ID required with approved=true."},"rebuy":{"type":"boolean","description":"Quote expired Microsoft license replacement; requires fresh approval."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_managed_inboxes_recover"]}},"/api/cli/managed-inboxes/registrant":{"get":{"operationId":"managed_inboxes.registrant","tags":["Managed inboxes"],"summary":"Managed inboxes registrant","description":"Read this workspace's domain-registration contact.\n\nMCP: `oxygen_managed_inbox_registrant`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_managed_inbox_registrant"]}},"/api/cli/managed-inboxes/subscribe":{"post":{"operationId":"postManagedInboxesSubscribe","tags":["Managed inboxes"],"summary":"Subscribe Managed Inboxes","description":"Quotes/buys inboxes on new, Cloudflare or Oxygen-owned domains. Existing previews: ownership, occupancy, credential/DNS scope; zero registration charge. Owned managed zones use Oxygen's credential; your Cloudflare zones use your token. The order removes listed email DNS. Preview saves nothing. A domain with inboxes: oxygen_managed_inboxes_add_mailboxes. Preview returns `mailboxes`, `senders`, `addons`, `addons_monthly_credits`, `warmup_activation`, total_monthly_credits and quote_id. `avatar_durable=false` withholds the photo; those inboxes ship permanently faceless. Warmup authority requires `warmup_activation.automatic_after_provisioning=true`; never infer it from selection. scope=warmup_only: Google transport=inboxkit_managed_google_handoff; Microsoft/Azure transport=inboxkit_sequencer_export. Both have mailbox_credentials_required=false and native_send_oauth_separate=true: warmup needs no supplied password/OAuth or second approval. Sending needs a verified grant for each exact mailbox; another mailbox's token proves nothing. Unavailable warmup costs 0 and warmup_activation is null; approve to buy without it. oxygen_mailboxes_warmup_enable is for existing inboxes. Approve quote_id to buy; max_mailboxes_per_domain narrows caps including existing addresses. Poll oxygen_managed_inboxes_get. First order: billing.\n\nMCP: `oxygen_managed_inboxes_subscribe`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"addons":{"type":"object","description":"Per-inbox add-ons: warmup defaults on, placement off. Selection and live availability are hashed into quote_id: approved=true must repeat the fresh preview. Warmup authority exists only when the response also carries warmup_activation.automatic_after_provisioning=true.","properties":{"warmup":{"type":"boolean","description":"Select email warm-up. It authorizes automatic post-provisioning activation only when the quote says available=true and carries warmup_activation; an unavailable selected line costs 0 and grants no authority."},"placement":{"type":"boolean","description":"Inbox placement: spam-placement tests, blacklist/reputation monitoring, auth checks; tests included rather than billed per run."}}},"approved":{"type":"boolean","description":"Required true (with quote_id) to place the order, start inbox billing, and authorize only selected AND available add-ons for the preview's exact mailboxes; otherwise returns a priced preview."},"billing":{"type":"object","description":"Registrant (WHOIS) contact for the domain — a registrar needs a REAL registrant, so this is required on the FIRST subscribe for an org with no vendor account yet (omit later; it is on file). Name defaults to the user's. snake_case keys are also accepted.","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"company":{"type":"string"},"country":{"type":"string","description":"ISO country code (e.g. US)."},"city":{"type":"string"},"addressLineOne":{"type":"string"},"addressLineTwo":{"type":"string"},"state":{"type":"string"},"postalCode":{"type":"string"},"phoneCc":{"type":"string","description":"Country calling code (e.g. 1)."},"phone":{"type":"string"},"languagePreference":{"type":"string"}},"required":["country","city","addressLineOne","state","postalCode","phone"],"additionalProperties":false},"connect_only":{"type":"object","additionalProperties":false,"description":"existing_domain only: connect without buying, 0 credits. approved=true with the preview signature removes its listed email DNS and connects.","properties":{"approved":{"type":"boolean"},"signature":{"type":"string"}}},"dns_cleanup":{"type":"object","additionalProperties":false,"description":"Optional standalone email-record deletion; approved orders already include the listed cleanup. approved=true plus plan_hash deletes only these IDs, never connects or buys. Not with order approved=true.","properties":{"record_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":6},"approved":{"type":"boolean"},"plan_hash":{"type":"string"}},"required":["record_ids"]},"domain":{"type":"string","description":"Sending domain (e.g. send.acme.com)."},"existing_domain":{"type":"boolean","description":"Use an existing Cloudflare domain from oxygen_domains_list. Preview is read-only; approval connects only this domain and buys mailboxes without registration or transfer."},"mailboxes":{"type":"array","items":{"type":"object","description":"sender_profile_id: name/photo (typed fields ignored, not an error), or first_name + last_name. Stamped PERMANENTLY.","properties":{"username":{"type":"string","description":"Use natural variants of the real sender (phil, p.hirte); avoid numbers unless explicitly requested."},"sender_profile_id":{"type":"string","description":"The sender owning this address (oxygen_senders_profiles_list). Several may share one."},"first_name":{"type":"string"},"last_name":{"type":"string"},"profile_picture_url":{"type":"string","description":"Optional avatar: a public, PERMANENT https URL."}},"required":["username"],"additionalProperties":false},"minItems":1,"description":"Mailboxes to provision on the domain (>= 1). Capped by platform: 5 for google/microsoft, 100 for azure."},"max_mailboxes_per_domain":{"type":"integer","minimum":1,"maximum":100,"description":"Save a stricter limit with the approved order, including existing addresses; preview does not save it. Use 2 for at most two per domain. Cannot exceed the platform cap."},"provider":{"type":"string","enum":["google","microsoft","azure"],"description":"Mailbox PLATFORM (not the vendor) — google (Gmail), microsoft (Graph), or azure (a dedicated tenant: 100 mailboxes per domain instead of 5)."},"quote_id":{"type":"string","description":"The quote_id from a fresh preview. Required when approved=true."},"redirect_url":{"type":"string","description":"Where the domain's web root redirects. Defaults to the workspace website."},"vendor":{"type":"string","enum":["inboxkit"],"description":"Pin the VENDOR we buy from. Omit to let OXYGEN choose. A named vendor whose credential is absent FAILS (409) rather than falling back to another vendor's wallet."},"years":{"type":"number","description":"Registration years for a NEW domain (1-10). Omit for existing domains."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_managed_inboxes_subscribe"]}},"/api/cli/managed-inboxes/verify":{"get":{"operationId":"getManagedInboxesVerify","tags":["Managed inboxes"],"summary":"Verify Managed Inbox Billing","description":"Compares purchased inbox inventory with the vendor and legacy Stripe mailbox seats. Credit-billed orders do not require Stripe seats; credit captures and renewal amounts remain explicitly unverified. Unavailable reads are verification gaps, never agreement or underbilling. Returns findings with who loses money: `customer_overbilled` outranks `oxygen_pays`. Call after subscribe/cancel or when billing looks wrong. Read-only, 0 credits.\n\nMCP: `oxygen_managed_inboxes_verify`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_managed_inboxes_verify"]}},"/api/cli/message-reviews":{"get":{"operationId":"getMessageReviews","tags":["Message reviews"],"summary":"List Message Reviews","description":"Lists AI-generated outreach message reviews. Reviews are created automatically when an AI column with reviewRequired=true completes.\n\nMCP: `oxygen_reviews_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","accepted","rejected","superseded"]}},{"name":"tableId","in":"query","required":false,"schema":{}},{"name":"table_id","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_reviews_list"]}},"/api/cli/message-reviews/decide":{"post":{"operationId":"postMessageReviewsDecide","tags":["Message reviews"],"summary":"Decide Message Review","description":"Accept or reject a review. Rejected highlights propose a playbook bullet for approval. auto_rerun re-quotes and caps its AI cell before deciding.\n\nMCP: `oxygen_reviews_decide`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"autoRerun":{},"auto_rerun":{"type":"boolean","description":"When true and decision is reject, trigger a single-row rerun."},"decision":{"type":"string","enum":["accept","reject"]},"highlights":{"type":"array","items":{"type":"object","description":"Character-span highlight on the prior message text.","properties":{"start":{"type":"integer","minimum":0},"end":{"type":"integer","minimum":1},"comment":{"type":"string","minLength":1,"maxLength":2000}},"required":["start","end","comment"],"additionalProperties":false},"maxItems":50},"id":{"type":"string"},"reviewId":{},"review_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_reviews_decide"]}},"/api/cli/message-reviews/next":{"get":{"operationId":"getMessageReviewsNext","tags":["Message reviews"],"summary":"Get Next Pending Review","description":"Returns the oldest pending message review across the workspace, optionally scoped to a table. Use this to drive a one-at-a-time human review queue.\n\nMCP: `oxygen_reviews_next`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableId","in":"query","required":false,"schema":{}},{"name":"table_id","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_reviews_next"]}},"/api/cli/messages":{"get":{"operationId":"getMessages","tags":["Messages"],"summary":"Search Messages Across Channels","description":"Full-text search across every individual email, LinkedIn and WhatsApp message in the org — message-level, not conversation-level (use oxygen_inbox_list to triage threads). Pass q to search message bodies; results come back as the most-relevant matches (one ranked page). Without q, returns the newest messages, paged via next_cursor (a page cut for context resumes from the last message returned). Filter by channel (all / email / linkedin / whatsapp), channels (csv subset), direction, account (mailbox or sender id), contact (name/handle), status and a since/until window. sequence_id (campaign) is EMAIL-ONLY — setting it restricts results to email, since LinkedIn/WhatsApp DMs carry no campaign link.\n\nMCP: `oxygen_messages_query`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"channels","in":"query","required":false,"schema":{"type":"string","description":"Optional comma-separated channel subset to include (email,linkedin,whatsapp). Empty = all three. Superseded by channel when channel is not 'all'."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_messages_query"]}},"/api/cli/messages/stats":{"get":{"operationId":"getMessagesStats","tags":["Messages"],"summary":"Inbox Message Analytics","description":"INBOX-WIDE analytics over the org's whole message corpus. NOT campaign performance: it counts every conversation, including mail no campaign sent, so its reply rate is not a campaign rate — use oxygen_sequences_analytics for that. Outbound/inbound/conversation totals, a conversation-level reply rate (has-inbound over has-outbound), response-time p50/p90, breakdowns by channel, campaign and status, top counterpart domains, and winning openers (ranked by replies earned). Counts and response time are exact; reply rate and opener ranking are heuristic. Scope with sequence_id, channel and a since/until window.\n\nMCP: `oxygen_messages_stats`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"channels","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_messages_stats"]}},"/api/cli/migrations/clay":{"post":{"operationId":"clay.migration","tags":["Migrations"],"summary":"Migrate from Clay","description":"Migrate a Clay workspace into Oxygen: connect, discover configuration, inspect samples or export complete responses, transfer table and Audience rows, checkpoint native rebuilds and reconcile coverage. Creates no paid runs or active schedules. Complete exports (--full): 8 MiB data + 1 MiB envelope. Full discovery omits derived resources; report retains dispositions and targets.\n\nMCP: `oxygen_clay_migration`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["connect","status","discover","read","transfer","checkpoint","report","disconnect"]},"migration_id":{"type":"string","minLength":1,"maxLength":200},"source_workspace_id":{"type":"string","minLength":1,"maxLength":200},"resource_type":{"type":"string","enum":["workspace","folder","workbook","table","audience","workflow","function","claygent","knowledge","schedule","campaign"]},"resource_id":{"type":"string","minLength":1,"maxLength":256},"row_id":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9_-]*$","description":"Source row ID for table read section=row; retains structured cell fields separately from displayed values."},"section":{"type":"string","enum":["metadata","columns","rows","row","graph","fields","record_ids","records","sequence"]},"full":{"type":"boolean","description":"Export one entire adapter response (8 MiB data + 1 MiB envelope); config credential redaction applies. No path/text projection. Discover omits derived resources; use report for dispositions/targets."},"path":{"type":"string","minLength":1,"maxLength":1000,"description":"Dotted path or JSON pointer into a source response, e.g. cells.f_1.fields."},"text_offset":{"type":"integer","minimum":0,"maximum":8388608,"description":"Continue a large scalar read at next_text_offset."},"entity_type":{"type":"string","enum":["people","companies","deals"]},"archived":{"type":"boolean","description":"Read archived Audience IDs instead of the default scope; only read section=record_ids. Transfer scope is pinned by resource_id."},"record_ids":{"type":"array","items":{"type":"integer","minimum":1},"minItems":1,"maxItems":100},"cursor":{"type":"string","maxLength":4000},"limit":{"type":"integer","minimum":1,"maximum":100},"target_table":{"type":"string","minLength":1,"maxLength":200},"source_cells_column":{"type":"string","minLength":1,"maxLength":200,"description":"Existing JSON column preserving original Clay cells; default clay_source_cells."},"source_row_id_column":{"type":"string","minLength":1,"maxLength":200,"description":"Existing text column for stable source row IDs; default clay_source_row_id."},"mapping":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"source_column_id":{"type":"string","minLength":1,"maxLength":200},"target_column":{"type":"string","minLength":1,"maxLength":200}},"required":["source_column_id","target_column"]},"minItems":1,"maxItems":500,"description":"Source Clay column IDs or Audience field keys to existing Oxygen column keys."},"disposition":{"type":"string","enum":["pending","copied","rebuilt","needs_decision","unsupported","inaccessible","excluded","failed"]},"target_kind":{"type":"string","minLength":1,"maxLength":100},"target_id":{"type":"string","minLength":1,"maxLength":200},"notes":{"type":"string","maxLength":8000}},"required":["action"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_clay_migration"]}},"/api/cli/notetaker/calendar":{"post":{"operationId":"notetaker.calendar.schedule","tags":["Notetaker"],"summary":"Notetaker calendar schedule","description":"Schedule recording for an existing calendar event after approval; an external CLI or MCP caller must supply an explicit max_credits ceiling.\n\nCLI: `oxygen notetaker calendar schedule`.\n\nMCP: `oxygen_notetaker_calendar_connect`, `oxygen_notetaker_calendar_schedule`, `oxygen_notetaker_calendar_sync`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event_id":{"type":"string"},"approved":{"type":"boolean"},"max_credits":{"type":"number","minimum":0}},"required":["event_id","approved"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_notetaker_calendar_connect","oxygen_notetaker_calendar_schedule","oxygen_notetaker_calendar_sync"],"x-oxygen-cli-command":"oxygen notetaker calendar schedule"}},"/api/cli/notetaker/desktop-upload":{"post":{"operationId":"notetaker.desktop_upload","tags":["Notetaker"],"summary":"Notetaker desktop upload","description":"Prepare an approved desktop meeting recording and its scoped upload URL. Upload and completion remain separate steps.\n\nCLI: `oxygen notetaker desktop-upload`.\n\nMCP: `oxygen_notetaker_desktop_upload_prepare`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"title":{"type":"string"},"max_minutes":{"type":"integer","minimum":1},"crm_links":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"object":{"type":"string"},"row_id":{"type":"string"},"role":{"type":"string"}},"required":["object","row_id"]}}},"required":["approved"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_notetaker_desktop_upload_prepare"],"x-oxygen-cli-command":"oxygen notetaker desktop-upload"}},"/api/cli/notetaker/schedule":{"post":{"operationId":"postNotetakerSchedule","tags":["Notetaker"],"summary":"Schedule Notetaker","description":"Schedules a Recall invited meeting bot. Defaults to dry_run and returns the credit estimate. Live scheduling requires live=true or mode='live', approved=true, and max_credits at or above the estimate.\n\nMCP: `oxygen_notetaker_schedule`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Explicit approval for the live paid Recall bot schedule."},"crmLinks":{},"crm_links":{"type":"array","description":"CRM records that should receive the meeting activity on their timeline.","items":{"type":"object","description":"CRM record to link the meeting note to.","properties":{"object":{"type":"string","description":"CRM object slug (companies, people).","minLength":1,"maxLength":120},"row_id":{"type":"string","description":"CRM record row id.","minLength":1,"maxLength":120},"role":{"type":"string","description":"Role of the linked record in the meeting, such as account, attendee, or opportunity.","minLength":1,"maxLength":120}},"additionalProperties":false,"required":["object","row_id"]},"maxItems":20},"join_at":{"type":"string","description":"ISO date-time for scheduled bot join.","minLength":1,"maxLength":80},"live":{"type":"boolean","description":"Shortcut for mode='live'. Omit or set false for dry-run."},"max_credits":{"type":"number","description":"Required spend cap for live schedules.","exclusiveMinimum":0},"max_minutes":{"type":"integer","minimum":1,"description":"Maximum meeting minutes to reserve.","maximum":480},"meetingUrl":{},"meeting_url":{"type":"string","description":"Zoom, Google Meet, or Teams meeting URL.","minLength":1,"maxLength":2000},"mode":{"type":"string","description":"Execution mode. Defaults to dry_run. Use live only after inspecting the preview.","enum":["dry_run","live"]},"title":{"type":"string","description":"Meeting title for the CRM timeline.","minLength":1,"maxLength":300}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_notetaker_schedule"]}},"/api/cli/notetaker/sessions/{sessionId}":{"get":{"operationId":"getNotetakerSessionsSessionId","tags":["Notetaker"],"summary":"Get Notetaker Session","description":"Gets one notetaker session, including Recall status, artifacts, linked CRM activity id, and credit reservation/usage state.\n\nMCP: `oxygen_notetaker_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_notetaker_status"]}},"/api/cli/notetaker/sessions/{sessionId}/note":{"patch":{"operationId":"notetaker.note.edit","tags":["Notetaker"],"summary":"Notetaker notes edit","description":"Save the markdown note for one meeting session and return the committed note.\n\nCLI: `oxygen notetaker notes edit`.\n\nMCP: `oxygen_notetaker_note_edit`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"type":"string"}},"required":["markdown"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_notetaker_note_edit"],"x-oxygen-cli-command":"oxygen notetaker notes edit"}},"/api/cli/notetaker/setup":{"post":{"operationId":"postNotetakerSetup","tags":["Notetaker"],"summary":"Set Up Notetaker","description":"Configures the Recall-backed Oxygen Notetaker. Defaults to dry_run; pass mode='live' or live=true to save settings after reviewing the webhook URL and required Recall subscriptions.\n\nMCP: `oxygen_notetaker_setup`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"auto_record_scope":{},"bot_avatar_url":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"Meeting bot avatar URL; null or empty clears it."},"bot_name":{"type":"string","description":"Meeting bot display name. Defaults to Oxygen Notetaker.","minLength":1,"maxLength":100},"capture_mode":{},"consent_disclosure":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"Recording disclosure; null or empty restores the default disclosure."},"default_max_credits":{"type":"number","description":"Default spend cap for live schedules.","exclusiveMinimum":0},"default_max_minutes":{"type":"integer","minimum":1,"description":"Default maximum meeting minutes to reserve. Defaults to 60.","maximum":480},"enabled":{},"live":{"type":"boolean","description":"Shortcut for mode='live'. Omit or set false for dry-run."},"mode":{"type":"string","description":"Execution mode. Defaults to dry_run. Use live only after inspecting the preview.","enum":["dry_run","live"]},"retention_days":{"type":"integer","description":"Transcript/artifact retention window. Defaults to 30.","minimum":0,"maximum":365}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_notetaker_setup"]}},"/api/cli/observability/approvals":{"get":{"operationId":"getObservabilityApprovals","tags":["Observability"],"summary":"List Pending Approvals","description":"Workspace-wide approvals inbox across workflow approvals, publishing posts, AI message reviews, inbox reply drafts, and collaboration approval requests (a named human's go/no-go). Read-only — each item carries the exact approve command (decide_hint), hint_kind, and web_url. Lists only; never approves.\n\nMCP: `oxygen_observability_approvals`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Optional source filter.","enum":["workflow","publishing","message_review","inbox_draft","collab_request"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_observability_approvals"]}},"/api/cli/observability/events":{"get":{"operationId":"getObservabilityEvents","tags":["Observability"],"summary":"List Observability Events","description":"Lists recent CLI/API operation events and provider request events for the active organization. Useful for debugging failed runs by trace id.\n\nMCP: `oxygen_observability_events`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_observability_events"]}},"/api/cli/observability/runs":{"get":{"operationId":"getObservabilityRuns","tags":["Observability"],"summary":"List Workspace Runs","description":"Workspace-wide runs lens: active and failed runs across workflows and table runs (search/sourcing included), newest first. Read-only — each item carries decide_hint, hint_kind, and web_url. Defaults to active + failed.\n\nMCP: `oxygen_observability_runs`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_observability_runs"]}},"/api/cli/onboarding/activation":{"get":{"operationId":"onboarding.activation.status","tags":["Onboarding"],"summary":"Onboarding status","description":"Resume your guided onboarding and native resource links. Requires enabled onboarding and current non-client membership.\n\nCLI: `oxygen onboarding activation status`.\n\nMCP: `oxygen_onboarding_activation_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_onboarding_activation_status"],"x-oxygen-cli-command":"oxygen onboarding activation status"},"post":{"operationId":"onboarding.activation.start","tags":["Onboarding"],"summary":"Start onboarding record","description":"Prepare your creator-only activation and Oxygent chat: Workspace shared, Personal creator-only. Free; no send or outreach.\n\nCLI: `oxygen onboarding activation start`.\n\nMCP: `oxygen_onboarding_activation_start`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"operating_path":{"type":"string","enum":["own_agent","oxygent"]}},"required":["operating_path"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_onboarding_activation_start"],"x-oxygen-cli-command":"oxygen onboarding activation start"}},"/api/cli/onboarding/activation/{activationId}":{"get":{"operationId":"onboarding.activation.get","tags":["Onboarding"],"summary":"Read onboarding record","description":"Read your activation by ID and its native resource links.\n\nCLI: `oxygen onboarding activation get`.\n\nMCP: `oxygen_onboarding_activation_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"activationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_onboarding_activation_get"],"x-oxygen-cli-command":"oxygen onboarding activation get"}},"/api/cli/onboarding/activation/{activationId}/first-leads":{"post":{"operationId":"onboarding.activation.first_leads","tags":["Onboarding"],"summary":"First leads Table","description":"Create or resume the activation-owned First leads Table. Free; no discovery, enrichment or outreach.\n\nCLI: `oxygen onboarding activation first-leads`.\n\nMCP: `oxygen_onboarding_activation_first_leads`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"activationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_onboarding_activation_first_leads"],"x-oxygen-cli-command":"oxygen onboarding activation first-leads"}},"/api/cli/onboarding/activation/{activationId}/resources":{"post":{"operationId":"onboarding.activation.link","tags":["Onboarding"],"summary":"Link onboarding resource","description":"Link an existing native onboarding resource at the expected revision. Does not create, enroll or send.\n\nCLI: `oxygen onboarding activation link`.\n\nMCP: `oxygen_onboarding_activation_link`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"activationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"revision":{"type":"integer","minimum":1},"resource":{"type":"string","enum":["knowledge","first_leads_table","sequence","sender"]},"resource_id":{"type":"string","minLength":1,"maxLength":160}},"required":["revision","resource","resource_id"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_onboarding_activation_link"],"x-oxygen-cli-command":"oxygen onboarding activation link"}},"/api/cli/onboarding/activation/{activationId}/routines/activate":{"post":{"operationId":"onboarding.activation.routine_activate","tags":["Onboarding"],"summary":"Activate daily routine","description":"Activate one exact routine preview at its native revision. Requires approval or valid current creator-chat auto-approve authority.\n\nCLI: `oxygen onboarding activation routine-activate`.\n\nMCP: `oxygen_onboarding_activation_routine_activate`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"activationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"purpose":{"type":"string","enum":["lead_scan","morning_briefing"]},"revision":{"type":"integer","minimum":1},"preview_token":{"type":"string","minLength":1,"maxLength":160},"approved":{"type":"boolean"},"approve_above_default":{"type":"boolean"}},"required":["purpose","revision","preview_token"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_onboarding_activation_routine_activate"],"x-oxygen-cli-command":"oxygen onboarding activation routine-activate"}},"/api/cli/onboarding/activation/{activationId}/routines/preview":{"post":{"operationId":"onboarding.activation.routines_preview","tags":["Onboarding"],"summary":"Review daily routines","description":"Save two routine draft configurations; review exact native source scope and caps. Arms no schedule.\n\nCLI: `oxygen onboarding activation routines-preview`.\n\nMCP: `oxygen_onboarding_activation_routines_preview`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"activationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"revision":{"type":"integer","minimum":1,"description":"Current activation revision from status/get (positive integer)."},"timezone":{"type":"string","minLength":1,"maxLength":80,"description":"Confirmed IANA timezone, e.g. Europe/Berlin."},"timezone_confirmed":{"type":"boolean","description":"True only after the user confirms this timezone."},"scan_time":{"type":"string","pattern":"^(?:[01]\\d|2[0-3]):[0-5]\\d$","description":"Scan start in HH:mm (00:00-23:59), local to timezone."},"briefing_time":{"type":"string","pattern":"^(?:[01]\\d|2[0-3]):[0-5]\\d$","description":"Briefing start in HH:mm (00:00-23:59), local to timezone."},"source_ids":{"type":"array","items":{"type":"string","minLength":1,"maxLength":160},"minItems":1,"maxItems":20,"description":"1-20 unique source IDs, comma-separated on CLI: table:<UUID> for a separate source Table or completed native people-search ingestion-run UUID."},"max_examined":{"type":"integer","minimum":1,"maximum":1000,"description":"Maximum source people examined per scan: integer 1-1000."},"max_new_leads":{"type":"integer","minimum":1,"maximum":100,"description":"Maximum review-only leads per scan: integer 1-100; no greater than max_examined."},"max_provider_pages":{"type":"integer","minimum":1,"maximum":100,"description":"Maximum provider pages per scan: integer 1-100."},"max_provider_credits":{"type":"number","minimum":0,"maximum":25000,"description":"Provider credit ceiling per scan: 0-25000; native Table sources quote 0."},"scan_per_run_credits":{"type":"number","minimum":0.01,"maximum":25000,"description":"Scan credit ceiling per run: 0.01-25000."},"scan_daily_credits":{"type":"number","minimum":0.01,"description":"Scan credit ceiling per rolling 24h: at least 0.01 and scan_per_run_credits."},"briefing_per_run_credits":{"type":"number","minimum":0.01,"maximum":25000,"description":"Briefing credit ceiling per run: 0.01-25000."},"briefing_daily_credits":{"type":"number","minimum":0.01,"description":"Briefing credit ceiling per rolling 24h: at least 0.01 and briefing_per_run_credits."}},"required":["revision","timezone","timezone_confirmed","scan_time","briefing_time","source_ids","max_examined","max_new_leads","max_provider_pages","max_provider_credits","scan_per_run_credits","scan_daily_credits","briefing_per_run_credits","briefing_daily_credits"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_onboarding_activation_routines_preview"],"x-oxygen-cli-command":"oxygen onboarding activation routines-preview"}},"/api/cli/onboarding/complete":{"post":{"operationId":"onboarding.complete","tags":["Onboarding"],"summary":"Onboarding complete","description":"Complete the active workspace's onboarding step and record its discovery-source choices. The other choice requires source_other.\n\nCLI: `oxygen onboarding complete`.\n\nMCP: `oxygen_onboarding_complete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sources":{"type":"array","items":{"type":"string","enum":["linkedin_content","linkedin_dm","linkedin_ads","x","youtube","google","ai_assistant","email","word_of_mouth","referral","event","other"]}},"source_other":{"type":"string"},"redirect_url":{"type":"string"}},"required":["sources"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_onboarding_complete"],"x-oxygen-cli-command":"oxygen onboarding complete"}},"/api/cli/onboarding/finish":{"post":{"operationId":"onboarding.finish","tags":["Onboarding"],"summary":"Onboarding finish","description":"Finish agent-led onboarding once a play is chosen: the onboarding Oxygent chat opens as an ordinary chat, without the Knowledge pane. If the chat holds your sent play, records your activation once. Spends nothing.\n\nCLI: `oxygen onboarding finish`.\n\nMCP: `oxygen_onboarding_finish`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_onboarding_finish"],"x-oxygen-cli-command":"oxygen onboarding finish"}},"/api/cli/onboarding/start":{"post":{"operationId":"onboarding.start","tags":["Onboarding"],"summary":"Onboarding start","description":"Answer onboarding's choice card. own_agent continues to connecting your own agent. copilot opens the Workspace Copilot with the onboarding conversation already started, billed in credits like any Copilot turn; choosing again reopens that conversation. restart (copilot) shows a finished onboarding again and asks the Oxygent to start over, as an ordinary send.\n\nCLI: `oxygen onboarding start`.\n\nMCP: `oxygen_onboarding_start`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","enum":["own_agent","copilot"]},"play":{"type":"string","description":"A play slug carried to the install step."},"restart":{"type":"boolean"}},"required":["path"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_onboarding_start"],"x-oxygen-cli-command":"oxygen onboarding start"}},"/api/cli/orgs":{"get":{"operationId":"getOrgs","tags":["Orgs"],"summary":"List Organizations","description":"Lists the OXYGEN workspaces this credential can reach, and which is active. An org-bound API key reaches only its own — `credential` says if it can switch.\n\nMCP: `oxygen_orgs_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_orgs_list"]}},"/api/cli/orgs/billing-link":{"post":{"operationId":"postOrgsBillingLink","tags":["Orgs"],"summary":"Link Workspace Billing","description":"One paid plan for multiple workspaces/agency clients, no duplicate payment. For no plan/ended trial/checkout asking another subscription, read oxygen_whoami billing_owner_candidates first. Payer: user-administered org on active paid plan, never a trial. Cancel this workspace's live subscription first. Owner funds credits; data access unchanged.\n\nMCP: `oxygen_orgs_billing_link`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"billing_owner_organization_id":{"type":"string","description":"Paying organization id, Clerk org id or slug from oxygen_whoami billing_owner_candidates or oxygen_orgs_list.","minLength":1,"maxLength":200},"monthly_credit_cap":{"type":"number","description":"Optional workspace monthly credit cap.","minimum":0},"organization_id":{"type":"string","description":"Workspace org id, Clerk org id or slug; default active org.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_orgs_billing_link"]}},"/api/cli/orgs/billing-owners":{"get":{"operationId":"orgs.billing_owners","tags":["Orgs"],"summary":"Orgs billing owners","description":"Read the current workspace's billing owner, entitlement and payer candidates, including ineligibility reasons. Optional organization asserts the current workspace. Free.\n\nMCP: `oxygen_workspace_billing_owners`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"organization","in":"query","required":false,"schema":{"type":"string","description":"Optional assertion of the current workspace's id, Clerk org id or slug. A mismatch fails before reading billing; this never selects another workspace."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_billing_owners"]}},"/api/cli/orgs/billing-unlink":{"post":{"operationId":"postOrgsBillingUnlink","tags":["Orgs"],"summary":"Unlink Workspace Billing","description":"Stops sharing a plan: restores a workspace to paying for its own credits, reversing oxygen_orgs_billing_link. Use it when a workspace should no longer be covered by another organization's subscription and will buy its own. This changes only credit billing, not workspace data access.\n\nMCP: `oxygen_orgs_billing_unlink`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"organization_id":{"type":"string","description":"Workspace organization id, Clerk org id, or slug. Defaults to the active organization.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_orgs_billing_unlink"]}},"/api/cli/orgs/create":{"post":{"operationId":"orgs.create","tags":["Orgs"],"summary":"Orgs create","description":"Create a workspace for the authenticated person's account and begin native company setup. Workspace API keys cannot create personal workspaces.\n\nCLI: `oxygen orgs create`.\n\nMCP: `oxygen_workspace_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"company_domain":{"type":"string","description":"Company website or domain, or its LinkedIn company page URL when it has no website."},"linkedin_profile_url":{"type":"string","description":"Creator's LinkedIn profile URL, separate from the company's page."}},"required":["name","company_domain"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workspace_create"],"x-oxygen-cli-command":"oxygen orgs create"}},"/api/cli/people/search/plan":{"post":{"operationId":"postPeopleSearchPlan","tags":["People"],"summary":"Plan People Search","description":"Canonical people/contact search: compiles prompt + persona filters into provider routes, table columns, gates, credit/match estimates, filter coverage, and workspace context. Use here instead of oxygen_search_*, oxygen_sourcing_plan or oxygen_lead_sourcing_plan.\nCOST: free (no paid provider calls; runs at most ONE free zero-credit people-count probe — on by default, pass estimate=false to skip it).\nFILTERS: pass typed `filters` (titles, seniorities, departments, ISO alpha-2 countries, contactability has-email/has-phone, nested company scope). extracted_filters.unparsed_constraint_hints reports unparsed constraints; per-route filter_application reports applied/dropped filters (only ContactOut honors contactability).\nSOURCE: source={table, linkedin_url_column} searches each company LinkedIn URL in that column, priced per company page (see the plan); people link back to their company row.\nFOLLOW-UP: _plan -> _run (dry_run) -> _run (live, approved=true, max_credits) -> oxygen_table_ingestions_wait -> oxygen_tables_preview. Upsert-dedupes on linkedin_url.\n\nMCP: `oxygen_people_search_plan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"estimate":{"type":"boolean","description":"Free sizing-before-spend is ON by default: a single FREE provider count probe (zero credits) populates estimated_match_count. Pass estimate=false to skip it (e.g. latency-sensitive or fully-automated calls). The probe never spends credits — it only runs a free count op the org can run for free, else returns a deterministic guess."},"filters":{"type":"object","description":"Typed people-search filters. Explicit filters merge OVER filters extracted from the prompt (explicit wins per path). All fields optional; an empty object means no constraints.","additionalProperties":false,"properties":{"titles":{"type":"object","description":"Job-title matching.","additionalProperties":false,"properties":{"include":{"type":"array","description":"Primary job titles (e.g. VP of Sales, Head of Revenue).","items":{"type":"string"}},"include_adjacent":{"type":"array","description":"Looser/adjacent titles accepted as matches.","items":{"type":"string"}},"exclude":{"type":"array","description":"Job titles to exclude.","items":{"type":"string"}},"match_mode":{"type":"string","enum":["keyword","exact"],"description":"include matching: keyword (default, full-text, best recall) or exact (literal title)."}}},"seniorities":{"type":"object","description":"Seniority levels (e.g. C-Suite, VP, Director, Manager, Staff) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"departments":{"type":"object","description":"Departments / functions (e.g. Sales, Marketing, Engineering) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"job_functions":{"type":"array","description":"Employee Finder job functions (e.g. Sales, Marketing).","items":{"type":"string"}},"names":{"type":"object","description":"Person names to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"keywords":{"type":"object","description":"Free-text persona keywords (headline / skills) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"headline_match":{"type":"boolean","description":"When true, also match titles against the LinkedIn headline (looser recall)."},"geo":{"type":"object","description":"Person location constraints.","additionalProperties":false,"properties":{"countries":{"type":"array","description":"ISO 3166-1 alpha-2 country codes, uppercase (e.g. US, DE, GB).","items":{"type":"string"}},"regions":{"type":"array","description":"Regions or sales territories.","items":{"type":"string"}},"continents":{"type":"array","description":"Continents (e.g. Europe, North America).","items":{"type":"string"}},"sales_regions":{"type":"array","description":"Sales regions (e.g. EMEA, NAMER, APAC).","items":{"type":"string"}},"cities":{"type":"object","description":"Cities to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}}}},"contactability":{"type":"object","description":"Reachability pre-filters (applied where the provider supports them; reported as dropped otherwise).","additionalProperties":false,"properties":{"require_work_email":{"type":"boolean","description":"Only return people with a work email available."},"require_mobile":{"type":"boolean","description":"Only return people with a phone/mobile available."},"email_status":{"type":"array","description":"Acceptable email verification statuses (e.g. verified).","items":{"type":"string"}}}},"company":{"type":"object","description":"Account scope — restrict people to companies matching these dimensions.","additionalProperties":false,"properties":{"domains":{"type":"object","description":"Company domains to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"names":{"type":"object","description":"Company names to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"linkedin_urls":{"type":"array","description":"Company LinkedIn URLs.","items":{"type":"string"}},"industries":{"type":"object","description":"Company industries to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"employee_count":{"type":"object","description":"Company live employee count range. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"employee_range":{"type":"array","description":"Company self-reported size bands (51-200).","items":{"type":"string"}},"technologies":{"type":"object","description":"Company technologies used to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}}}},"min_connections":{"type":"number","description":"Minimum LinkedIn connection count.","minimum":0,"maximum":500},"education":{"type":"object","description":"Education phrases (school, degree, year) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"max_results_per_company":{"type":"number","description":"Cap on contacts returned per company for account-anchored searches.","minimum":1,"maximum":200},"native_filters":{"type":"object","additionalProperties":true}}},"materialize_preview":{"type":"boolean","description":"When true, create an Oxygen preview table containing route rows."},"prompt":{"type":"string","description":"Natural-language people/contact search request. Required unless `source` is given.","minLength":1,"maxLength":20000},"source":{"type":"object","description":"Companies table to fan the Employee Finder over; implies source_intent account_contacts.","additionalProperties":false,"required":["table","linkedin_url_column"],"properties":{"table":{"type":"string","description":"Table id or slug holding the companies."},"linkedin_url_column":{"type":"string","description":"Column key holding each company's LinkedIn URL."},"company_offset":{"type":"number","description":"Skip this many companies.","minimum":0},"company_limit":{"type":"number","description":"Source at most this many companies.","minimum":1}}},"source_intent":{"type":"string","description":"Optional intent override: persona_search, account_contacts, audience_sizing, profile_lookup, concept_persona, or fallback_broad."},"target_count":{"type":"number","description":"Desired contact count for routing and estimates. Maximum 50,000 per plan; larger populations require segmented plans.","minimum":1,"maximum":50000}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_people_search_plan"]}},"/api/cli/people/search/preview":{"get":{"operationId":"getPeopleSearchPreview","tags":["People"],"summary":"Preview People Search","description":"Up to 50 people free; action=filters. Table: oxygen_people_search_plan then oxygen_people_search_run with same source and typed filters. Otherwise run source=people_search + native source_filters.\n\nMCP: `oxygen_people_search_preview`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"filters","in":"query","required":false,"schema":{"type":"object","description":"E.g. {people:{job_title:{include:[\"VP Sales\"]}},company:{linkedin_url:[...]}}; {} searches all.","additionalProperties":true}},{"name":"source","in":"query","required":false,"schema":{"type":"object","description":"{table, linkedin_url_column}: free 50-company sample."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_people_search_preview"]},"post":{"operationId":"postPeopleSearchPreview","tags":["People"],"summary":"Preview People Search","description":"Up to 50 people free; action=filters. Table: oxygen_people_search_plan then oxygen_people_search_run with same source and typed filters. Otherwise run source=people_search + native source_filters.\n\nMCP: `oxygen_people_search_preview`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"filters":{"type":"object","description":"E.g. {people:{job_title:{include:[\"VP Sales\"]}},company:{linkedin_url:[...]}}; {} searches all.","additionalProperties":true},"source":{"type":"object","description":"{table, linkedin_url_column}: free 50-company sample."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_people_search_preview"]}},"/api/cli/people/search/run":{"post":{"operationId":"postPeopleSearchRun","tags":["People"],"summary":"Run People Search","description":"Dry-runs or queues a live table ingestion run for one people-search provider route. This is the people-search executor; pair it with oxygen_people_search_plan, not oxygen_search_run.\nCOST: dry_run is free. Live requires approved=true and max_credits. max_pages is computed from target_count and capped by max_credits (see auto_paged). Required provider preflight blocks live until verified server-side. Rows upsert-dedupe on linkedin_url.\nFILTERS: when planning from a prompt, pass typed `filters` (and estimate) — identical schema to oxygen_people_search_plan. source=\"people_search\" + source_filters from oxygen_people_search_preview needs no prompt.\nSOURCE: source={table, linkedin_url_column} searches each company LinkedIn URL in that column, priced per company page (see the plan); people link back to their company row.\nTABLE: omit it, or match `output_columns`.\nFOLLOW-UP: this tool mode=dry_run -> mode=live, approved=true -> oxygen_table_ingestions_wait -> oxygen_tables_preview.\n\nMCP: `oxygen_people_search_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required for live runs after inspecting dry-run output."},"continue":{"type":"boolean","description":"With table: resume where the last run of this search into it stopped, so a repeat finds new people; refuses unspent when none are left."},"estimate":{"type":"boolean","description":"Free sizing-before-spend is ON by default: a single FREE provider count probe (zero credits) populates estimated_match_count. Pass estimate=false to skip it (e.g. latency-sensitive or fully-automated calls). The probe never spends credits — it only runs a free count op the org can run for free, else returns a deterministic guess."},"filters":{"type":"object","description":"Typed people-search filters. Explicit filters merge OVER filters extracted from the prompt (explicit wins per path). All fields optional; an empty object means no constraints.","additionalProperties":false,"properties":{"titles":{"type":"object","description":"Job-title matching.","additionalProperties":false,"properties":{"include":{"type":"array","description":"Primary job titles (e.g. VP of Sales, Head of Revenue).","items":{"type":"string"}},"include_adjacent":{"type":"array","description":"Looser/adjacent titles accepted as matches.","items":{"type":"string"}},"exclude":{"type":"array","description":"Job titles to exclude.","items":{"type":"string"}},"match_mode":{"type":"string","enum":["keyword","exact"],"description":"include matching: keyword (default, full-text, best recall) or exact (literal title)."}}},"seniorities":{"type":"object","description":"Seniority levels (e.g. C-Suite, VP, Director, Manager, Staff) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"departments":{"type":"object","description":"Departments / functions (e.g. Sales, Marketing, Engineering) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"job_functions":{"type":"array","description":"Employee Finder job functions (e.g. Sales, Marketing).","items":{"type":"string"}},"names":{"type":"object","description":"Person names to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"keywords":{"type":"object","description":"Free-text persona keywords (headline / skills) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"headline_match":{"type":"boolean","description":"When true, also match titles against the LinkedIn headline (looser recall)."},"geo":{"type":"object","description":"Person location constraints.","additionalProperties":false,"properties":{"countries":{"type":"array","description":"ISO 3166-1 alpha-2 country codes, uppercase (e.g. US, DE, GB).","items":{"type":"string"}},"regions":{"type":"array","description":"Regions or sales territories.","items":{"type":"string"}},"continents":{"type":"array","description":"Continents (e.g. Europe, North America).","items":{"type":"string"}},"sales_regions":{"type":"array","description":"Sales regions (e.g. EMEA, NAMER, APAC).","items":{"type":"string"}},"cities":{"type":"object","description":"Cities to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}}}},"contactability":{"type":"object","description":"Reachability pre-filters (applied where the provider supports them; reported as dropped otherwise).","additionalProperties":false,"properties":{"require_work_email":{"type":"boolean","description":"Only return people with a work email available."},"require_mobile":{"type":"boolean","description":"Only return people with a phone/mobile available."},"email_status":{"type":"array","description":"Acceptable email verification statuses (e.g. verified).","items":{"type":"string"}}}},"company":{"type":"object","description":"Account scope — restrict people to companies matching these dimensions.","additionalProperties":false,"properties":{"domains":{"type":"object","description":"Company domains to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"names":{"type":"object","description":"Company names to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"linkedin_urls":{"type":"array","description":"Company LinkedIn URLs.","items":{"type":"string"}},"industries":{"type":"object","description":"Company industries to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"employee_count":{"type":"object","description":"Company live employee count range. Bounds inclusive.","additionalProperties":false,"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"employee_range":{"type":"array","description":"Company self-reported size bands (51-200).","items":{"type":"string"}},"technologies":{"type":"object","description":"Company technologies used to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}}}},"min_connections":{"type":"number","description":"Minimum LinkedIn connection count.","minimum":0,"maximum":500},"education":{"type":"object","description":"Education phrases (school, degree, year) to include and/or exclude.","additionalProperties":false,"properties":{"include":{"type":"array","items":{"type":"string"}},"exclude":{"type":"array","items":{"type":"string"}}}},"max_results_per_company":{"type":"number","description":"Cap on contacts returned per company for account-anchored searches.","minimum":1,"maximum":200},"native_filters":{"type":"object","additionalProperties":true}}},"max_credits":{"type":"number","description":"Required credit ceiling for live runs.","minimum":0},"max_pages":{"type":"number","description":"Maximum provider pages to ingest. If omitted, Oxygen auto-computes it from target_count (see auto_paged). With `source` it means pages PER COMPANY.","minimum":1,"maximum":1000},"mode":{"type":"string","description":"dry_run or live. Defaults to dry_run."},"plan":{"type":"object","description":"Full people plan with routes; an id alone is not a retrievable plan reference. Or preview with prompt + identical filters.","required":["id","source_prompt","recommended_route_id","routes"],"properties":{"id":{"type":"string"},"source_prompt":{"type":"string"},"recommended_route_id":{"type":"string"},"routes":{"type":"array","items":{"type":"object","additionalProperties":true}}},"additionalProperties":true},"project":{"type":"string","description":"Folder id or slug for the created table; ignored with `table`.","maxLength":200},"prompt":{"type":"string","description":"Natural-language people search request. Pass prompt, plan, or source.","minLength":1,"maxLength":20000},"route_id":{"type":"string","description":"Route id from the plan to execute.","minLength":1,"maxLength":200},"source":{"oneOf":[{"type":"object","description":"Companies table to fan the Employee Finder over; implies source_intent account_contacts.","additionalProperties":false,"required":["table","linkedin_url_column"],"properties":{"table":{"type":"string","description":"Table id or slug holding the companies."},"linkedin_url_column":{"type":"string","description":"Column key holding each company's LinkedIn URL."},"company_offset":{"type":"number","description":"Skip this many companies.","minimum":0},"company_limit":{"type":"number","description":"Source at most this many companies.","minimum":1}}},{"type":"string","enum":["people_search"],"description":"Find people from source_filters alone."}],"description":"Either the companies table to fan out over, or the string people_search with source_filters."},"source_filters":{"type":"object","description":"With source=people_search: the same nested filters as oxygen_people_search_preview; server validates every key.","additionalProperties":true},"source_intent":{"type":"string","description":"Optional intent override when planning from prompt."},"source_overrides":{"type":"object","description":"Move the company window over a submitted plan's source: company_limit 1 buys the first page, company_offset 1 sources the rest.","additionalProperties":false,"properties":{"company_offset":{"type":"number","description":"Skip this many companies.","minimum":0},"company_limit":{"type":"number","description":"Source at most this many companies.","minimum":1}}},"table":{"type":"string","description":"Existing table id or slug to receive rows. If omitted for live, Oxygen creates a table.","minLength":1,"maxLength":200},"table_name":{"type":"string","description":"Name the table this run creates. Ignored when `table` names an existing one."},"target_count":{"type":"number","description":"Desired contact count when planning from prompt.","minimum":1,"maximum":50000},"tool_id":{"type":"string","description":"Tool id from the plan to execute.","minLength":1,"maxLength":200},"upsert_key":{"type":"string","description":"Column key used for live upsert. Must match the plan upsert key (linkedin_url).","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_people_search_run"]}},"/api/cli/pricing/customer-credit-prices":{"get":{"operationId":"pricing.customer_credit_prices","tags":["Pricing"],"summary":"Pricing customer credit prices","description":"Read the customer credit-price catalog, quantity decisions and price provenance used by the Table picker.\n\nCLI: `oxygen pricing customer-credit-prices`.\n\nMCP: `oxygen_customer_credit_prices`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_customer_credit_prices"],"x-oxygen-cli-command":"oxygen pricing customer-credit-prices"}},"/api/cli/projects":{"get":{"operationId":"getProjects","tags":["Projects"],"summary":"Folders","description":"Lists active folders.\n\nMCP: `oxygen_projects_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_projects_list"]},"post":{"operationId":"postProjects","tags":["Projects"],"summary":"Create Folder","description":"Creates table folders.\n\nMCP: `oxygen_projects_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_projects_create"]}},"/api/cli/projects/{project}":{"patch":{"operationId":"patchProjectsProject","tags":["Projects"],"summary":"Rename Folder","description":"Renames table folder.\n\nMCP: `oxygen_projects_rename`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"project","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_projects_rename"]},"delete":{"operationId":"deleteProjectsProject","tags":["Projects"],"summary":"Delete Folder","description":"Preview/delete folder + tables; oxygen_tables_restore before the purge date restores both.\n\nMCP: `oxygen_projects_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"project","in":"path","required":true,"schema":{"type":"string"}},{"name":"confirm","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"expected_table_ids","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"live","in":"query","required":false,"schema":{}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["dry_run","live"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_projects_delete"]}},"/api/cli/projects/{project}/color":{"post":{"operationId":"postProjectsProjectColor","tags":["Projects"],"summary":"Folder Color","description":"Sets color; auto resets.\n\nMCP: `oxygen_projects_color`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"project","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"color":{"type":"string","enum":["gray","red","orange","amber","yellow","green","teal","blue","indigo","purple","pink","auto"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_projects_color"]}},"/api/cli/projects/{project}/tags":{"post":{"operationId":"postProjectsProjectTags","tags":["Projects"],"summary":"Tag Folder","description":"Sets tags; [] clears.\n\nMCP: `oxygen_projects_tag`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"project","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_projects_tag"]}},"/api/cli/publishing/amplification":{"get":{"operationId":"getPublishingAmplification","tags":["Publishing"],"summary":"Publishing Amplification Policies","description":"Standing engagement from named accounts, paced and capped. list/get/actions read; create/update/enable/disable/delete govern policies. create needs approved=true and both caps, lands DISABLED; enable also needs approved=true. Armed policies make public writes and spend credits. disable skips pending actions. list/actions MCP default 20 rows; windows refuse whole on oversize.\n\nMCP: `oxygen_publishing_amplification`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"enabled","in":"query","required":false,"schema":{"type":"boolean","description":"list: true enabled, false disabled; omit for both."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":500,"x-clamp":true,"description":"list policies max 200; actions ledger max 500. Newest first; 0 uses 100."}},{"name":"scope_kind","in":"query","required":false,"schema":{"type":"string","description":"list scope; create: all/tag/post with matching target.","enum":["all","tag","post","ugc_program","ugc_peer_program"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_amplification"]},"post":{"operationId":"postPublishingAmplification","tags":["Publishing"],"summary":"Publishing Amplification Policies","description":"Standing engagement from named accounts, paced and capped. list/get/actions read; create/update/enable/disable/delete govern policies. create needs approved=true and both caps, lands DISABLED; enable also needs approved=true. Armed policies make public writes and spend credits. disable skips pending actions. list/actions MCP default 20 rows; windows refuse whole on oversize.\n\nMCP: `oxygen_publishing_amplification`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"actions":{"type":"array","items":{"type":"string","enum":["reaction","comment","repost"]},"description":"What participants do. Required for create."},"approved":{"type":"boolean","description":"Required true for create and enable: the standing grant to act from those accounts within the caps."},"commentPool":{},"comment_delay_max_seconds":{"type":"integer","minimum":0},"comment_delay_min_seconds":{"type":"integer","minimum":0},"comment_pool":{"type":"array","items":{"type":"string","minLength":1,"maxLength":1000},"description":"Comments are drawn from this pool, never generated. Required when actions includes comment."},"comment_source":{},"max_actions_per_post":{"type":"integer","minimum":1,"description":"Hard cap per post. Required for create — no cap, no policy."},"max_credits_per_cycle":{"type":"number","exclusiveMinimum":0,"description":"Hard credit cap per cycle. Required for create — no cap, no policy."},"metadata":{"type":"object","additionalProperties":true,"description":"Policy metadata; {} clears on update."},"name":{"type":"string","description":"Required for create.","minLength":1,"maxLength":200},"participantSenderIds":{},"participant_sender_ids":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"description":"Connected sender accounts that will engage. Required for create."},"reaction_delay_max_seconds":{"type":"integer","minimum":0},"reaction_delay_min_seconds":{"type":"integer","minimum":0},"risk_acknowledged":{"type":"boolean","description":"Required true for create and enable: LinkedIn may restrict accounts used for automation."},"scope_kind":{"type":"string","description":"list scope; create: all/tag/post with matching target.","enum":["all","tag","post","ugc_program","ugc_peer_program"]},"scope_post_id":{"type":"string","maxLength":120},"scope_tag":{"type":"string","maxLength":80}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_amplification"]}},"/api/cli/publishing/amplification/{policyId}":{"get":{"operationId":"getPublishingAmplificationPolicyId","tags":["Publishing"],"summary":"Publishing Amplification Policies","description":"Standing engagement from named accounts, paced and capped. list/get/actions read; create/update/enable/disable/delete govern policies. create needs approved=true and both caps, lands DISABLED; enable also needs approved=true. Armed policies make public writes and spend credits. disable skips pending actions. list/actions MCP default 20 rows; windows refuse whole on oversize.\n\nMCP: `oxygen_publishing_amplification`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"policyId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_amplification"]},"patch":{"operationId":"patchPublishingAmplificationPolicyId","tags":["Publishing"],"summary":"Publishing Amplification Policies","description":"Standing engagement from named accounts, paced and capped. list/get/actions read; create/update/enable/disable/delete govern policies. create needs approved=true and both caps, lands DISABLED; enable also needs approved=true. Armed policies make public writes and spend credits. disable skips pending actions. list/actions MCP default 20 rows; windows refuse whole on oversize.\n\nMCP: `oxygen_publishing_amplification`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"policyId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"actions":{"type":"array","items":{"type":"string","enum":["reaction","comment","repost"]},"description":"What participants do. Required for create."},"commentPool":{},"comment_delay_max_seconds":{"type":"integer","minimum":0},"comment_delay_min_seconds":{"type":"integer","minimum":0},"comment_pool":{"type":"array","items":{"type":"string","minLength":1,"maxLength":1000},"description":"Comments are drawn from this pool, never generated. Required when actions includes comment."},"comment_source":{},"max_actions_per_post":{"type":"integer","minimum":1,"description":"Hard cap per post. Required for create — no cap, no policy."},"max_credits_per_cycle":{"type":"number","exclusiveMinimum":0,"description":"Hard credit cap per cycle. Required for create — no cap, no policy."},"metadata":{"type":"object","additionalProperties":true,"description":"Policy metadata; {} clears on update."},"name":{"type":"string","description":"Required for create.","minLength":1,"maxLength":200},"participantSenderIds":{},"participant_sender_ids":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"description":"Connected sender accounts that will engage. Required for create."},"reaction_delay_max_seconds":{"type":"integer","minimum":0},"reaction_delay_min_seconds":{"type":"integer","minimum":0},"risk_acknowledged":{"type":"boolean","description":"Required true for create and enable: LinkedIn may restrict accounts used for automation."},"scope_post_id":{"type":"string","maxLength":120},"scope_tag":{"type":"string","maxLength":80}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_amplification"]},"delete":{"operationId":"deletePublishingAmplificationPolicyId","tags":["Publishing"],"summary":"Publishing Amplification Policies","description":"Standing engagement from named accounts, paced and capped. list/get/actions read; create/update/enable/disable/delete govern policies. create needs approved=true and both caps, lands DISABLED; enable also needs approved=true. Armed policies make public writes and spend credits. disable skips pending actions. list/actions MCP default 20 rows; windows refuse whole on oversize.\n\nMCP: `oxygen_publishing_amplification`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"policyId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_amplification"]}},"/api/cli/publishing/amplification/{policyId}/actions":{"get":{"operationId":"getPublishingAmplificationPolicyIdActions","tags":["Publishing"],"summary":"Publishing Amplification Policies","description":"Standing engagement from named accounts, paced and capped. list/get/actions read; create/update/enable/disable/delete govern policies. create needs approved=true and both caps, lands DISABLED; enable also needs approved=true. Armed policies make public writes and spend credits. disable skips pending actions. list/actions MCP default 20 rows; windows refuse whole on oversize.\n\nMCP: `oxygen_publishing_amplification`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"policyId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":500,"x-clamp":true,"description":"list policies max 200; actions ledger max 500. Newest first; 0 uses 100."}},{"name":"post_id","in":"query","required":false,"schema":{"type":"string","description":"actions: scheduled post UUID filter."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["planned","dispatched","failed","skipped","effect_unknown"],"description":"action=actions ledger filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_amplification"]}},"/api/cli/publishing/amplification/{policyId}/disable":{"post":{"operationId":"postPublishingAmplificationPolicyIdDisable","tags":["Publishing"],"summary":"Publishing Amplification Policies","description":"Standing engagement from named accounts, paced and capped. list/get/actions read; create/update/enable/disable/delete govern policies. create needs approved=true and both caps, lands DISABLED; enable also needs approved=true. Armed policies make public writes and spend credits. disable skips pending actions. list/actions MCP default 20 rows; windows refuse whole on oversize.\n\nMCP: `oxygen_publishing_amplification`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"policyId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_amplification"]}},"/api/cli/publishing/amplification/{policyId}/enable":{"post":{"operationId":"postPublishingAmplificationPolicyIdEnable","tags":["Publishing"],"summary":"Publishing Amplification Policies","description":"Standing engagement from named accounts, paced and capped. list/get/actions read; create/update/enable/disable/delete govern policies. create needs approved=true and both caps, lands DISABLED; enable also needs approved=true. Armed policies make public writes and spend credits. disable skips pending actions. list/actions MCP default 20 rows; windows refuse whole on oversize.\n\nMCP: `oxygen_publishing_amplification`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"policyId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"risk_acknowledged":{"type":"boolean","description":"Required true for create and enable: LinkedIn may restrict accounts used for automation."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_amplification"]}},"/api/cli/publishing/analytics/account":{"get":{"operationId":"getPublishingAnalyticsAccount","tags":["Publishing"],"summary":"Publishing Analytics","description":"Stored LinkedIn/X snapshots; no provider call. summary ranks posts, by tag too; timeseries: earned trends, followers; export: posts with tags and metrics; post/account: metric rows (MCP default 20); set_cpm writes EMV config. snapshotted_posts counts sync passes, metric coverage known values. Null is unknown, never zero; null_reasons explains it. Read freshness and guidance for refresh delays.\n\nMCP: `oxygen_publishing_analytics`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"channel","in":"query","required":false,"schema":{"type":"string","enum":["linkedin","x"],"description":"summary/timeseries channel. Defaults to linkedin; export omitted = both."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":400,"description":"post/account: total metric rows, newest first (not per account); 0 uses 90. summary: top posts, max 50. timeseries ignores it."}},{"name":"provider","in":"query","required":false,"schema":{"type":"string","enum":["linkedin","x","instagram","tiktok","facebook","youtube"],"description":"scope=account filter. Omit for all."}},{"name":"since","in":"query","required":false,"schema":{"type":"string","description":"ISO start date; account/post use since, not from/to."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_analytics"]}},"/api/cli/publishing/analytics/emv":{"post":{"operationId":"postPublishingAnalyticsEmv","tags":["Publishing"],"summary":"Publishing Analytics","description":"Stored LinkedIn/X snapshots; no provider call. summary ranks posts, by tag too; timeseries: earned trends, followers; export: posts with tags and metrics; post/account: metric rows (MCP default 20); set_cpm writes EMV config. snapshotted_posts counts sync passes, metric coverage known values. Null is unknown, never zero; null_reasons explains it. Read freshness and guidance for refresh delays.\n\nMCP: `oxygen_publishing_analytics`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"cpm":{"type":"object","additionalProperties":true,"description":"Required for set_cpm, e.g. {\"linkedin\": 30}."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_analytics"]}},"/api/cli/publishing/analytics/export":{"get":{"operationId":"getPublishingAnalyticsExport","tags":["Publishing"],"summary":"Publishing Analytics","description":"Stored LinkedIn/X snapshots; no provider call. summary ranks posts, by tag too; timeseries: earned trends, followers; export: posts with tags and metrics; post/account: metric rows (MCP default 20); set_cpm writes EMV config. snapshotted_posts counts sync passes, metric coverage known values. Null is unknown, never zero; null_reasons explains it. Read freshness and guidance for refresh delays.\n\nMCP: `oxygen_publishing_analytics`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"channel","in":"query","required":false,"schema":{"type":"string","enum":["linkedin","x"],"description":"summary/timeseries channel. Defaults to linkedin; export omitted = both."}},{"name":"format","in":"query","required":false,"schema":{}},{"name":"from","in":"query","required":false,"schema":{"type":"string","description":"summary/timeseries/export inclusive start date."}},{"name":"range","in":"query","required":false,"schema":{"type":"string","enum":["7d","30d","90d","365d"],"description":"summary/timeseries/export window. Defaults to 30d."}},{"name":"to","in":"query","required":false,"schema":{"type":"string","description":"summary/timeseries/export inclusive end date."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_analytics"]}},"/api/cli/publishing/analytics/posts/{postId}":{"get":{"operationId":"getPublishingAnalyticsPostsPostId","tags":["Publishing"],"summary":"Publishing Analytics","description":"Stored LinkedIn/X snapshots; no provider call. summary ranks posts, by tag too; timeseries: earned trends, followers; export: posts with tags and metrics; post/account: metric rows (MCP default 20); set_cpm writes EMV config. snapshotted_posts counts sync passes, metric coverage known values. Null is unknown, never zero; null_reasons explains it. Read freshness and guidance for refresh delays.\n\nMCP: `oxygen_publishing_analytics`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":400,"description":"post/account: total metric rows, newest first (not per account); 0 uses 90. summary: top posts, max 50. timeseries ignores it."}},{"name":"since","in":"query","required":false,"schema":{"type":"string","description":"ISO start date; account/post use since, not from/to."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_analytics"]}},"/api/cli/publishing/analytics/summary":{"get":{"operationId":"getPublishingAnalyticsSummary","tags":["Publishing"],"summary":"Publishing Analytics","description":"Stored LinkedIn/X snapshots; no provider call. summary ranks posts, by tag too; timeseries: earned trends, followers; export: posts with tags and metrics; post/account: metric rows (MCP default 20); set_cpm writes EMV config. snapshotted_posts counts sync passes, metric coverage known values. Null is unknown, never zero; null_reasons explains it. Read freshness and guidance for refresh delays.\n\nMCP: `oxygen_publishing_analytics`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"channel","in":"query","required":false,"schema":{"type":"string","enum":["linkedin","x"],"description":"summary/timeseries channel. Defaults to linkedin; export omitted = both."}},{"name":"from","in":"query","required":false,"schema":{"type":"string","description":"summary/timeseries/export inclusive start date."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":400,"description":"post/account: total metric rows, newest first (not per account); 0 uses 90. summary: top posts, max 50. timeseries ignores it."}},{"name":"range","in":"query","required":false,"schema":{"type":"string","enum":["7d","30d","90d","365d"],"description":"summary/timeseries/export window. Defaults to 30d."}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["engagements","impressions","reactions","comments","reposts"],"description":"summary ranking. Defaults to engagements."}},{"name":"to","in":"query","required":false,"schema":{"type":"string","description":"summary/timeseries/export inclusive end date."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_analytics"]}},"/api/cli/publishing/analytics/timeseries":{"get":{"operationId":"getPublishingAnalyticsTimeseries","tags":["Publishing"],"summary":"Publishing Analytics","description":"Stored LinkedIn/X snapshots; no provider call. summary ranks posts, by tag too; timeseries: earned trends, followers; export: posts with tags and metrics; post/account: metric rows (MCP default 20); set_cpm writes EMV config. snapshotted_posts counts sync passes, metric coverage known values. Null is unknown, never zero; null_reasons explains it. Read freshness and guidance for refresh delays.\n\nMCP: `oxygen_publishing_analytics`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"channel","in":"query","required":false,"schema":{"type":"string","enum":["linkedin","x"],"description":"summary/timeseries channel. Defaults to linkedin; export omitted = both."}},{"name":"from","in":"query","required":false,"schema":{"type":"string","description":"summary/timeseries/export inclusive start date."}},{"name":"range","in":"query","required":false,"schema":{"type":"string","enum":["7d","30d","90d","365d"],"description":"summary/timeseries/export window. Defaults to 30d."}},{"name":"to","in":"query","required":false,"schema":{"type":"string","description":"summary/timeseries/export inclusive end date."}},{"name":"tz","in":"query","required":false,"schema":{"type":"string","description":"timeseries IANA zone. Defaults to UTC.","maxLength":64}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_analytics"]}},"/api/cli/publishing/comment-replies/{actionId}/approve":{"post":{"operationId":"postPublishingCommentRepliesActionIdApprove","tags":["Publishing"],"summary":"Publishing Community","description":"Read and triage Publishing Community, the local public-comment queue for owned posts. list/get make no provider call; update/resolve are local. Completed coverage counts earlier successful polls and can overlap failed coverage after a later error. preview_reply freezes text without posting. approve_reply is the sole REAL public write and requires approved=true with its action_id and content_hash. Comments belong to Posts, not Unibox.\n\nMCP: `oxygen_publishing_comments`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Must be true for the REAL write."},"content_hash":{"type":"string","description":"preview_reply SHA-256; required to approve.","minLength":64,"maxLength":64}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_comments"]}},"/api/cli/publishing/comments":{"get":{"operationId":"getPublishingComments","tags":["Publishing"],"summary":"Publishing Community","description":"Read and triage Publishing Community, the local public-comment queue for owned posts. list/get make no provider call; update/resolve are local. Completed coverage counts earlier successful polls and can overlap failed coverage after a later error. preview_reply freezes text without posting. approve_reply is the sole REAL public write and requires approved=true with its action_id and content_hash. Comments belong to Posts, not Unibox.\n\nMCP: `oxygen_publishing_comments`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"assignee","in":"query","required":false,"schema":{"type":"string","description":"list actor id or me.","maxLength":120}},{"name":"channel","in":"query","required":false,"schema":{"type":"string","description":"list channel; default linkedin.","maxLength":40}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"list next_cursor.","maxLength":2000}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"list size."}},{"name":"post_id","in":"query","required":false,"schema":{"type":"string","description":"list post filter.","maxLength":120}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["needs_reply","draft","awaiting_approval","replied","resolved","ignored","spam","action_unavailable"],"description":"Exact list/update state; omit when using view."}},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["all","unanswered"],"description":"list view; unanswered is default. all covers published owned posts within 30 days plus UGC-linked posts, not lifetime history."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_comments"]}},"/api/cli/publishing/comments/{commentId}":{"get":{"operationId":"getPublishingCommentsCommentId","tags":["Publishing"],"summary":"Publishing Community","description":"Read and triage Publishing Community, the local public-comment queue for owned posts. list/get make no provider call; update/resolve are local. Completed coverage counts earlier successful polls and can overlap failed coverage after a later error. preview_reply freezes text without posting. approve_reply is the sole REAL public write and requires approved=true with its action_id and content_hash. Comments belong to Posts, not Unibox.\n\nMCP: `oxygen_publishing_comments`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_comments"]},"patch":{"operationId":"patchPublishingCommentsCommentId","tags":["Publishing"],"summary":"Publishing Community","description":"Read and triage Publishing Community, the local public-comment queue for owned posts. list/get make no provider call; update/resolve are local. Completed coverage counts earlier successful polls and can overlap failed coverage after a later error. preview_reply freezes text without posting. approve_reply is the sole REAL public write and requires approved=true with its action_id and content_hash. Comments belong to Posts, not Unibox.\n\nMCP: `oxygen_publishing_comments`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"assignee_actor_id":{"type":"string","description":"update assignee.","maxLength":120},"draft_body":{"type":"string","description":"update local draft; never posts.","minLength":1,"maxLength":20000},"notes":{"type":"string","description":"update private notes.","maxLength":20000},"status":{"type":"string","enum":["needs_reply","draft","awaiting_approval","replied","resolved","ignored","spam","action_unavailable"],"description":"Exact list/update state; omit when using view."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_comments"]}},"/api/cli/publishing/comments/{commentId}/reply-actions":{"post":{"operationId":"postPublishingCommentsCommentIdReplyActions","tags":["Publishing"],"summary":"Publishing Community","description":"Read and triage Publishing Community, the local public-comment queue for owned posts. list/get make no provider call; update/resolve are local. Completed coverage counts earlier successful polls and can overlap failed coverage after a later error. preview_reply freezes text without posting. approve_reply is the sole REAL public write and requires approved=true with its action_id and content_hash. Comments belong to Posts, not Unibox.\n\nMCP: `oxygen_publishing_comments`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"Exact preview_reply text.","minLength":1,"maxLength":20000},"idempotency_key":{"type":"string","description":"preview retry key.","maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_comments"]}},"/api/cli/publishing/comments/{commentId}/resolve":{"post":{"operationId":"postPublishingCommentsCommentIdResolve","tags":["Publishing"],"summary":"Publishing Community","description":"Read and triage Publishing Community, the local public-comment queue for owned posts. list/get make no provider call; update/resolve are local. Completed coverage counts earlier successful polls and can overlap failed coverage after a later error. preview_reply freezes text without posting. approve_reply is the sole REAL public write and requires approved=true with its action_id and content_hash. Comments belong to Posts, not Unibox.\n\nMCP: `oxygen_publishing_comments`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"resolution":{"type":"string","enum":["resolved","ignored","spam","needs_reply"],"description":"Local outcome; default resolved."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_comments"]}},"/api/cli/publishing/drafts":{"get":{"operationId":"getPublishingDrafts","tags":["Publishing"],"summary":"List Publishing Drafts","description":"Lists AI post drafts awaiting a human decision. Defaults to the open queue (queued + edited).\n\nMCP: `oxygen_publishing_drafts_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["ai","idea"],"description":"Filter by draft kind."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Max drafts. Defaults to 50."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["queued","edited","accepted","rejected"],"description":"Filter by one status. Omit for the open queue."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_drafts_list"]},"post":{"operationId":"postPublishingDrafts","tags":["Publishing"],"summary":"Add a Publishing Idea","description":"Files a content idea into the backlog — a draft with kind=idea and no publish time. Free: no AI call, nothing scheduled. Read them back with oxygen_publishing_drafts_list(kind=idea), and turn one into a needs-approval post with oxygen_publishing_draft_accept(publish_at).\n\nMCP: `oxygen_publishing_idea_add`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"channels":{"type":"array","items":{"type":"string","enum":["linkedin","x","instagram","tiktok","facebook","youtube"]},"description":"Channels this idea is meant for."},"kind":{},"target_channels":{},"text":{"type":"string","description":"The idea.","minLength":1,"maxLength":5000},"topic":{"type":"string","description":"Optional topic tag.","maxLength":300}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_idea_add"]}},"/api/cli/publishing/drafts/{draftId}":{"patch":{"operationId":"publishing.drafts.update","tags":["Publishing"],"summary":"Publishing drafts edit","description":"Edit a queued publishing draft's text without publishing it.\n\nMCP: `oxygen_publishing_draft_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"},"variant_index":{"type":"integer","minimum":0}},"required":["text"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_draft_update"]}},"/api/cli/publishing/drafts/{draftId}/accept":{"post":{"operationId":"postPublishingDraftsDraftIdAccept","tags":["Publishing"],"summary":"Accept Publishing Draft","description":"Accepts one draft variant into the publish queue as a NEEDS-APPROVAL post. It does not publish: approve the post separately.\n\nMCP: `oxygen_publishing_draft_accept`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["linkedin","x","instagram","tiktok","facebook","youtube"],"description":"Channel override. Defaults to the draft's first target."},"providerConnectionId":{},"provider_connection_id":{"type":"string","description":"Connected provider account id.","minLength":1,"maxLength":200},"publishAt":{},"publish_at":{"type":"string","description":"ISO date-time; without an offset, wall-clock time in timezone, else UTC.","minLength":1,"maxLength":80},"senderAccountId":{},"sender_account_id":{"type":"string","description":"LinkedIn sender id.","minLength":1,"maxLength":120},"timezone":{"type":"string","description":"IANA zone for publish_at without an offset; default UTC.","minLength":1,"maxLength":80},"variant_index":{"type":"integer","minimum":0,"description":"Which variant (0-based). Default 0."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_draft_accept"]}},"/api/cli/publishing/drafts/{draftId}/reject":{"post":{"operationId":"postPublishingDraftsDraftIdReject","tags":["Publishing"],"summary":"Reject Publishing Draft","description":"Rejects a post draft. The reason is filed to the Knowledge Graph, so later drafts learn what this workspace will not publish.\n\nMCP: `oxygen_publishing_draft_reject`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"draftId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Why it was rejected.","minLength":1,"maxLength":500}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_draft_reject"]}},"/api/cli/publishing/import":{"post":{"operationId":"postPublishingImport","tags":["Publishing"],"summary":"Import Publishing Posts","description":"Bulk-loads scheduled posts from rows or a CSV string. dry_run=true (the DEFAULT) parses, lints, and reports invalid rows while writing NOTHING — inspect that before passing dry_run=false. Imported rows land as needs-approval drafts: import never approves and never publishes. A row carrying an idempotency_key it already used is skipped, so a re-import cannot duplicate the queue.\n\nMCP: `oxygen_publishing_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"csv":{"type":"string","description":"CSV text with a header row, instead of rows.","minLength":1,"maxLength":200000},"dryRun":{},"dry_run":{"type":"boolean","description":"Defaults to true. Pass false to write."},"rows":{"type":"array","description":"Each row needs content_text + publish_at; it may also carry sender_account_id, provider, timezone, title, first_comment, tags[], and idempotency_key. A publish_at without Z or an offset is wall-clock time in the row's timezone, else its sender's, else UTC.","items":{"type":"object","additionalProperties":true,"properties":{"content_text":{"type":"string","minLength":1},"publish_at":{"type":"string","minLength":1}},"required":["content_text","publish_at"]},"minItems":1,"maxItems":500},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"Unified workspace tags applied to every imported post."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_import"]}},"/api/cli/publishing/media/{mediaId}/uploaded":{"post":{"operationId":"postPublishingMediaMediaIdUploaded","tags":["Publishing"],"summary":"Mark Publishing Media Uploaded","description":"Verifies a Publishing media object exists in storage and marks the durable media asset uploaded.\n\nMCP: `oxygen_publishing_media_uploaded`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"mediaId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"sha256":{"type":"string","description":"Optional SHA-256 digest for provenance.","minLength":1,"maxLength":128}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_media_uploaded"]}},"/api/cli/publishing/media/upload-url":{"post":{"operationId":"postPublishingMediaUploadUrl","tags":["Publishing"],"summary":"Create Publishing Media Upload URL","description":"Creates media and an upload_url. PUT byte_length with upload_headers, then mark uploaded.\n\nMCP: `oxygen_publishing_media_upload_url`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"byte_length":{"type":"integer","minimum":1,"description":"Exact byte length of the media object."},"contentType":{},"content_type":{"type":"string","description":"MIME type; send the same value in upload_headers.","minLength":3,"maxLength":160},"fileName":{},"file_name":{"type":"string","description":"Original media filename.","minLength":1,"maxLength":300},"metadata":{"type":"object","description":"Optional media metadata.","additionalProperties":true},"scheduledPostId":{},"scheduled_post_id":{"type":"string","description":"Provenance only; does not attach. Use content.media_asset_ids.","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_media_upload_url"]}},"/api/cli/publishing/mentions/resolve":{"post":{"operationId":"postPublishingMentionsResolve","tags":["Publishing"],"summary":"Resolve LinkedIn Mentions","description":"Checks that the LinkedIn identities a post references (@handles, /in/ and /company/ URLs, provider ids, URNs) exist and returns their profiles; it never changes the post. Tag inline in content_text: approval resolves each @tag and blocks on one it cannot, so use this to catch a wrong handle early. source=sender (default) is a free read through the connected account, bound by its working-hours window and read budget; source=scraper is the managed cookieless lookup (no sender or window needed) requiring approved=true + max_credits — fetch its current request-shaped price through tool discovery and dry-run rather than relying on a copied number. Ambiguous handles resolve company-first on both sources.\n\nMCP: `oxygen_publishing_mentions_resolve`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"LinkedIn sender id, connection id, or Unipile account id. Required for source=sender; ignored for source=scraper."},"approved":{"type":"boolean","description":"Approve the paid scraper lookups (required with source=scraper)."},"content_text":{},"identifiers":{"type":"array","description":"Explicit identities to resolve: { value, kind?: person|company, as_mention?: boolean } objects (bare strings also accepted).","items":{"type":"object","additionalProperties":true}},"maxCredits":{},"max_credits":{"type":"number","description":"Credit ceiling for scraper lookups (required with source=scraper)."},"senderAccountId":{},"sender_account_id":{},"source":{"type":"string","enum":["sender","scraper"],"description":"Resolution source. Defaults to sender (free)."},"text":{"type":"string","description":"Post text containing @identifiers or LinkedIn URLs."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_mentions_resolve"]}},"/api/cli/publishing/mentions/search":{"post":{"operationId":"publishing.mentions.search","tags":["Publishing"],"summary":"Publishing mentions search","description":"Find LinkedIn company or person identities for a mention; free, subject to the connected account's read quota.\n\nCLI: `oxygen publishing mentions search`.\n\nMCP: `oxygen_publishing_mentions_search`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"kind":{"type":"string","enum":["company","person"]},"connection_id":{"type":"string"}},"required":["query"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_mentions_search"],"x-oxygen-cli-command":"oxygen publishing mentions search"}},"/api/cli/publishing/posts":{"get":{"operationId":"getPublishingPosts","tags":["Publishing"],"summary":"List Publishing Posts","description":"Lists stored Publishing posts. Continue with next_cursor and identical filters; no provider call.\n\nMCP: `oxygen_publishing_posts_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"approval_status","in":"query","required":false,"schema":{"type":"string","enum":["draft","needs_approval","approved","rejected"],"description":"Optional approval-state filter."}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"The previous page's next_cursor. Keep the same filters and order."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Maximum posts to return. Defaults to 100."}},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["oldest","newest"],"description":"Publish-time order. Defaults to oldest."}},{"name":"provider","in":"query","required":false,"schema":{"type":"string","enum":["linkedin","x","instagram","tiktok","facebook","youtube"],"description":"Optional provider filter."}},{"name":"sender_account_id","in":"query","required":false,"schema":{"type":"string","description":"Only posts belonging to this connected sender in the active workspace."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","scheduled","queued","publishing","published","failed","canceled"],"description":"Optional queue status filter."}},{"name":"tag","in":"query","required":false,"schema":{"type":"string","description":"Only posts carrying this workspace tag.","maxLength":80}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_posts_list"]},"post":{"operationId":"postPublishingPosts","tags":["Publishing"],"summary":"Create Publishing Post","description":"Saves a personal post in Publishing; nothing publishes until oxygen_publishing_posts_approve. status draft keeps it off the schedule for the user to read first; ugc_participation_id saves an unapproved program draft. One post on several channels: create the first, then each other channel with group_with, its own account and copy.\n\nMCP: `oxygen_publishing_posts_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Approval to publish when due; set true only after explicit user approval."},"channel":{"type":"string","enum":["linkedin","x","instagram","tiktok","facebook","youtube"],"description":"Channel; default provider."},"confirm_not_published":{},"content":{"type":"object","description":"LinkedIn attachments: base64 content, content_type, filename. Use media_asset_ids for uploads. content.mentions is rejected; scheduled_post_id is provenance. X: thread [{text,media_asset_ids}], poll {options,duration_minutes}, reply_settings, media_alt_text {id:text}, media_tagged_usernames.","properties":{"media_asset_ids":{"type":"array","description":"Canonical Oxygen media ids to attach at dispatch.","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":20},"media_asset_id":{"type":"string","description":"Legacy singular id; prefer media_asset_ids.","minLength":1,"maxLength":120},"attachments":{"type":"array","items":{"type":"object","properties":{"content":{"type":"string","description":"Standard base64.","minLength":4},"content_type":{"type":"string","minLength":3},"filename":{"type":"string","minLength":1,"maxLength":255}},"required":["content","content_type","filename"],"additionalProperties":false},"maxItems":20},"external_link":{"type":"string","description":"Provider external link.","maxLength":2000},"first_comment":{"type":"string","description":"Comment posted right after the post, e.g. the link. Not TikTok/Facebook."},"mentions":{"type":"array","description":"Must be empty; use @public-id in content_text.","items":{"type":"object","additionalProperties":true},"maxItems":0}},"additionalProperties":true},"contentText":{},"content_text":{"type":"string","description":"Text. LinkedIn tags: @<public-identifier> for a person, @<handle> from linkedin.com/company/<handle> for a page; see oxygen_publishing_mentions_resolve.","minLength":1,"maxLength":25000},"group_with":{"type":"string","description":"Post id: add this as another channel of that post (one per channel), publishing at its time; omit publish_at and timezone.","minLength":1,"maxLength":120},"idempotencyKey":{},"idempotency_key":{"type":"string","description":"Reuse for retries of the same creation."},"provider":{"type":"string","enum":["linkedin","x","instagram","tiktok","facebook","youtube"],"description":"Provider; default linkedin."},"providerConnectionId":{},"provider_connection_id":{"type":"string","description":"Composio connection; defaults active.","minLength":1,"maxLength":120},"publishAt":{},"publish_at":{"type":"string","description":"ISO date-time. With Z or an offset, that instant; without, wall-clock time in timezone. Required unless group_with.","minLength":1,"maxLength":80},"senderAccountId":{},"sender_account_id":{"type":"string","description":"Sender id from oxygen_senders_list; required for LinkedIn.","minLength":1,"maxLength":120},"status":{"type":"string","enum":["draft","scheduled"],"description":"draft: saved for review, needs no sender; default scheduled (draft with ugc_participation_id)."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"Unified workspace tags to apply."},"timezone":{"type":"string","description":"IANA zone, e.g. Europe/Berlin. Default: the sender's own zone, else UTC.","minLength":1,"maxLength":120},"title":{"type":"string","description":"YouTube/TikTok video title; elsewhere a queue label.","minLength":1,"maxLength":300},"ugc_participation_id":{"type":"string","description":"Active creator participation. Forces an unapproved LinkedIn draft; review it in Publishing → UGC."},"video_thumbnail_media_asset_id":{"type":"string","description":"Video cover for a LinkedIn video (JPEG/PNG) or Instagram Reel (JPEG, max 8 MB): an uploaded media id."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_create"]}},"/api/cli/publishing/posts/{postId}":{"get":{"operationId":"getPublishingPostsPostId","tags":["Publishing"],"summary":"Get Publishing Post","description":"Gets one scheduled Publishing post with its sender account, resolved media assets, preview URLs, provider result, and publish attempt history. A post on several channels lists them under group.\n\nMCP: `oxygen_publishing_posts_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_posts_get"]},"patch":{"operationId":"patchPublishingPostsPostId","tags":["Publishing"],"summary":"Update Publishing Post","description":"Updates editable draft, scheduled or failed posts; content edits revoke approval. Text edits keep mention_previews. Cached repairs must use the existing verified publicIdentifier: update text, raw, identifier and offsets, keeping identity fields. Resolve another company handle again; editing cannot verify a different page.\n\nMCP: `oxygen_publishing_posts_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{},"channel":{"type":"string","enum":["linkedin","x","instagram","tiktok","facebook","youtube"]},"confirm_not_published":{"type":"boolean","description":"Only after checking the account: an uncertain post is NOT live. Unlocks it."},"content":{"type":"object","description":"LinkedIn attachments: base64 content, content_type, filename. Use media_asset_ids for uploads. content.mentions is rejected; scheduled_post_id is provenance. X: thread [{text,media_asset_ids}], poll {options,duration_minutes}, reply_settings, media_alt_text {id:text}, media_tagged_usernames.","properties":{"media_asset_ids":{"type":"array","description":"Canonical Oxygen media ids to attach at dispatch.","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":20},"media_asset_id":{"type":"string","description":"Legacy singular id; prefer media_asset_ids.","minLength":1,"maxLength":120},"attachments":{"type":"array","items":{"type":"object","properties":{"content":{"type":"string","description":"Standard base64.","minLength":4},"content_type":{"type":"string","minLength":3},"filename":{"type":"string","minLength":1,"maxLength":255}},"required":["content","content_type","filename"],"additionalProperties":false},"maxItems":20},"external_link":{"type":"string","description":"Provider external link.","maxLength":2000},"first_comment":{"type":"string","description":"Comment posted right after the post, e.g. the link. Not TikTok/Facebook."},"mentions":{"type":"array","description":"Must be empty; use @public-id in content_text.","items":{"type":"object","additionalProperties":true},"maxItems":0}},"additionalProperties":true},"contentText":{},"content_merge":{"type":"object","description":"Merge content keys; null removes a key. Arrays, including mention_previews, are replaced whole: include every entry to keep.","additionalProperties":true},"content_text":{"type":"string","description":"Text. LinkedIn tags: @<public-identifier> for a person, @<handle> from linkedin.com/company/<handle> for a page; see oxygen_publishing_mentions_resolve.","minLength":1,"maxLength":25000},"idempotency_key":{},"provider":{"type":"string","enum":["linkedin","x","instagram","tiktok","facebook","youtube"]},"providerConnectionId":{},"provider_connection_id":{"type":"string","minLength":1,"maxLength":120},"publishAt":{},"publish_at":{"type":"string","description":"With Z or an offset, that instant; without, wall-clock time in timezone, else the post's. Moves every channel of the post that has not published.","minLength":1,"maxLength":80},"senderAccountId":{},"sender_account_id":{"type":"string","minLength":1,"maxLength":120},"status":{"type":"string","enum":["draft","scheduled"],"description":"Scheduling does not grant approval; use oxygen_publishing_posts_approve to authorize publication."},"tags":{},"timezone":{"type":"string","minLength":1,"maxLength":120},"title":{"type":"string","minLength":1,"maxLength":300},"ugc_participation_id":{},"video_thumbnail_media_asset_id":{"type":"string","description":"Video cover for a LinkedIn video (JPEG/PNG) or Instagram Reel (JPEG, max 8 MB): an uploaded media id."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_update"]},"delete":{"operationId":"deletePublishingPostsPostId","tags":["Publishing"],"summary":"Delete Publishing Post","description":"Deletes OXYGEN copies and settled history only; live platform posts stay intact. Allows unattempted queue posts and settled canceled/published copies. Published copies stay excluded from discovery. Refuses unresolved live actions or active amplification spend.\n\nMCP: `oxygen_publishing_posts_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_delete"]}},"/api/cli/publishing/posts/{postId}/approve":{"post":{"operationId":"postPublishingPostsPostIdApprove","tags":["Publishing"],"summary":"Approve Publishing Post","description":"Approves a draft or scheduled post for publish_at. Costs 0 credits. Owner-only profile approval: oxygen_senders_limits_set publishing_approval. LinkedIn checks person handles/page IDs before arming. Current resolved previews with handle mismatches fail before lookups. Company handles are rechecked through the sender and server identity cache; free provider reads may be needed even with stored previews. queued_at records first arming. Program drafts require UGC approval.\n\nMCP: `oxygen_publishing_posts_approve`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"all_channels":{"type":"boolean","description":"Approve every channel of this post still awaiting approval; all are checked first, reruns skip approved ones."},"confirm_not_published":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_approve"]}},"/api/cli/publishing/posts/{postId}/boost":{"post":{"operationId":"postPublishingPostsPostIdBoost","tags":["Publishing"],"summary":"Boost a Publishing Post","description":"One-off amplification of ONE post: creates a post-scoped, already-enabled policy and plans its actions immediately. These are REAL public reactions/comments from your teammates' connected LinkedIn accounts and they SPEND CREDITS, so approved=true and max_credits are both required and the call is refused without them. For a standing rule, use oxygen_publishing_amplification.\n\nMCP: `oxygen_publishing_posts_boost`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"actions":{"type":"array","items":{"type":"string","enum":["reaction","comment","repost"]},"description":"What each sender does."},"approved":{"type":"boolean","description":"Must be true. Without it the API refuses with approval_required and nothing is planned."},"commentPool":{},"comment_pool":{"type":"array","items":{"type":"string","minLength":1,"maxLength":1000},"description":"Comment texts to draw from. Required when actions includes comment."},"max_actions_per_post":{"type":"integer","minimum":1,"description":"Hard cap on actions planned."},"max_credits":{"type":"number","exclusiveMinimum":0,"description":"Credit ceiling for the boost. Required."},"name":{"type":"string","description":"Name the post-scoped policy."},"participant_sender_ids":{},"risk_acknowledged":{"type":"boolean","description":"Must be true: LinkedIn may restrict accounts used for automation."},"sender_account_ids":{},"senders":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"description":"Connected sender accounts that will engage."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_boost"]}},"/api/cli/publishing/posts/{postId}/cancel":{"post":{"operationId":"postPublishingPostsPostIdCancel","tags":["Publishing"],"summary":"Cancel Publishing Post","description":"Cancels a draft, scheduled, queued, or failed Publishing post and revokes its approval. oxygen_publishing_posts_uncancel reopens it as an unapproved draft; approve it again before it can publish.\n\nMCP: `oxygen_publishing_posts_cancel`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"all_channels":{},"confirm_not_published":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_cancel"]}},"/api/cli/publishing/posts/{postId}/comments":{"get":{"operationId":"getPublishingPostsPostIdComments","tags":["Publishing"],"summary":"Publishing Post Notes","description":"Internal post review notes. action=list|add|resolve; add replies with parent_comment_id, resolve settles a note or reopens it with resolved=false. list has resolved/limit filters and a whole-receipt window (MCP default 20 rows). Notes never publish, block, or approve a post.\n\nMCP: `oxygen_publishing_notes`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}},{"name":"after_comment_id","in":"query","required":false,"schema":{"type":"string","maxLength":120,"description":"list: seek after this private note in native oldest-first order, within this post and resolved filter."}},{"name":"comment_id","in":"query","required":false,"schema":{"type":"string","maxLength":120,"description":"list: exact private note on this post; resolve: note to settle/reopen."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":500,"description":"list private notes, oldest first; 0 uses native default 200."}},{"name":"resolved","in":"query","required":false,"schema":{"type":"boolean","description":"list: true resolved, false unresolved; omit for both. resolve: default true."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_publishing_notes"]},"post":{"operationId":"postPublishingPostsPostIdComments","tags":["Publishing"],"summary":"Publishing Post Notes","description":"Internal post review notes. action=list|add|resolve; add replies with parent_comment_id, resolve settles a note or reopens it with resolved=false. list has resolved/limit filters and a whole-receipt window (MCP default 20 rows). Notes never publish, block, or approve a post.\n\nMCP: `oxygen_publishing_notes`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"Note text. Required for add.","minLength":1,"maxLength":5000},"parent_comment_id":{"type":"string","description":"Reply to this note.","maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_notes"]}},"/api/cli/publishing/posts/{postId}/comments/{commentId}/resolve":{"post":{"operationId":"postPublishingPostsPostIdCommentsCommentIdResolve","tags":["Publishing"],"summary":"Publishing Post Notes","description":"Internal post review notes. action=list|add|resolve; add replies with parent_comment_id, resolve settles a note or reopens it with resolved=false. list has resolved/limit filters and a whole-receipt window (MCP default 20 rows). Notes never publish, block, or approve a post.\n\nMCP: `oxygen_publishing_notes`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"resolved":{"type":"boolean","description":"list: true resolved, false unresolved; omit for both. resolve: default true."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_notes"]}},"/api/cli/publishing/posts/{postId}/retry":{"post":{"operationId":"postPublishingPostsPostIdRetry","tags":["Publishing"],"summary":"Retry Publishing Post","description":"Moves a failed approved Publishing post back to scheduled so the worker can attempt it again on the next 5-minute scheduler tick.\n\nMCP: `oxygen_publishing_posts_retry`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"all_channels":{},"confirm_not_published":{"type":"boolean","description":"Only after checking the account: an uncertain post is NOT live. Unlocks it."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_retry"]}},"/api/cli/publishing/posts/{postId}/review":{"post":{"operationId":"postPublishingPostsPostIdReview","tags":["Publishing"],"summary":"Review Publishing Post","description":"Pre-publish review of one post: deterministic channel lint (free; error findings BLOCK approval) plus an AI voice/claims check against the Knowledge Graph (PAID, max_credits required; findings advise but never block).\n\nMCP: `oxygen_publishing_posts_review`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"max_credits":{"type":"number","exclusiveMinimum":0,"description":"Credit ceiling for the AI review call. Required."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_review"]}},"/api/cli/publishing/posts/{postId}/revisions":{"get":{"operationId":"getPublishingPostsPostIdRevisions","tags":["Publishing"],"summary":"Publishing Post Revisions","description":"Content history of one scheduled post. action=list reads newest-first revisions with limit and a whole-receipt window (MCP default 20 rows). action=restore rolls the post back to revision_number, snapshotting the current text as a fresh revision first, so a restore is itself undoable. Restore is refused once the post is publishing, published, or canceled.\n\nMCP: `oxygen_publishing_revisions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}},{"name":"before_revision","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"list: read revisions older than this number, newest first; native continuation of a limited history scope."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":200,"description":"list revisions, newest first; 0 uses native default 50."}},{"name":"revision_number","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"list: exact historical revision on this post; restore: revision to restore."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_revisions"]}},"/api/cli/publishing/posts/{postId}/revisions/{revisionNumber}/restore":{"post":{"operationId":"postPublishingPostsPostIdRevisionsRevisionNumberRestore","tags":["Publishing"],"summary":"Publishing Post Revisions","description":"Content history of one scheduled post. action=list reads newest-first revisions with limit and a whole-receipt window (MCP default 20 rows). action=restore rolls the post back to revision_number, snapshotting the current text as a fresh revision first, so a restore is itself undoable. Restore is refused once the post is publishing, published, or canceled.\n\nMCP: `oxygen_publishing_revisions`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}},{"name":"revisionNumber","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_publishing_revisions"]}},"/api/cli/publishing/posts/{postId}/tags":{"post":{"operationId":"postPublishingPostsPostIdTags","tags":["Publishing"],"summary":"Tag Publishing Posts","description":"Adds/removes unified workspace tags on a scheduled post. Tags are internal and never published.\n\nMCP: `oxygen_publishing_tags`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"add":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"Workspace tags to add."},"remove":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"Workspace tags to remove."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_tags"]}},"/api/cli/publishing/posts/{postId}/uncancel":{"post":{"operationId":"postPublishingPostsPostIdUncancel","tags":["Publishing"],"summary":"Uncancel Publishing Post","description":"Reopens a canceled post as an unapproved draft, keeping its publish time and attempt history. Approve it again to re-arm it.\n\nMCP: `oxygen_publishing_posts_uncancel`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"all_channels":{},"confirm_not_published":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_uncancel"]}},"/api/cli/publishing/posts/draft":{"post":{"operationId":"postPublishingPostsDraft","tags":["Publishing"],"summary":"Draft Publishing Posts","description":"Drafts post variants with AI, grounded in the workspace Knowledge Graph (voice, positioning, campaign learnings). PAID: one AI call, max_credits required. Writes drafts only — nothing schedules or publishes until a human accepts a draft and approves the post.\n\nMCP: `oxygen_publishing_posts_draft`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"channels":{"type":"array","items":{"type":"string","enum":["linkedin","x","instagram","tiktok","facebook","youtube"]},"description":"Target channels; shapes length/format rules."},"ground":{"type":"boolean","description":"Retrieve Knowledge Graph pages. Default true."},"max_credits":{"type":"number","exclusiveMinimum":0,"description":"Credit ceiling for the AI call. Required."},"sourceText":{},"sourceUrl":{},"source_text":{"type":"string","description":"Source to rewrite.","minLength":1,"maxLength":20000},"source_url":{"type":"string","description":"Source URL.","minLength":1,"maxLength":2000},"template":{"type":"string","enum":["summarize","repurpose","changelog","feature_launch","case_study","personal_story","startup_advice","company_milestone","hiring","fundraise","hook_generator","popular_questions","tech_stack","podcast_clip","hashtags"],"description":"Draft template. summarize/repurpose/podcast_clip/hashtags need a source; the rest need a topic."},"topic":{"type":"string","description":"What the post is about.","minLength":1,"maxLength":2000},"variants":{"type":"integer","minimum":1,"maximum":5,"description":"Angles to draft. Default 3."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_publishing_posts_draft"]}},"/api/cli/recipes":{"get":{"operationId":"getRecipes","tags":["Recipes"],"summary":"List Recipes","description":"Lists Oxygen recipes (GTM plays with prerequisites, credit posture, approval gates) ranked by relevance to query. Use when the user asks what to do; view summary to pick one, then oxygen_recipes_get.\n\nMCP: `oxygen_recipes_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"audience","in":"query","required":false,"schema":{"type":"string","description":"founder | gtm-operator | agency-operator.","maxLength":20}},{"name":"category","in":"query","required":false,"schema":{"type":"string","description":"start-here | pipeline-from-zero | catch-warm-signals | linkedin-engine | convert-faster | revenue-truth | agency-scale.","maxLength":40}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"description":"Max recipes, after ranking."}},{"name":"q","in":"query","required":false,"schema":{}},{"name":"query","in":"query","required":false,"schema":{"type":"string","description":"The goal in plain words; ranks the catalog.","maxLength":200}},{"name":"stage","in":"query","required":false,"schema":{"type":"string","description":"day-1 | day-7 | day-30 | ongoing.","maxLength":10}},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["summary","full"],"description":"summary: compact index; full (default): every field."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_recipes_list"]}},"/api/cli/recipes/apply":{"post":{"operationId":"postRecipesApply","tags":["Recipes"],"summary":"Apply Recipe Kit","description":"Installs a recipe's kit under one approval: every Blueprint stage in order — tables and columns created or reused, each Workflow registered DISABLED, an already-active stage skipped, a receipt written on the playbook page. 0 credits, no provider call, no external write. Enabling, paid runs and Sequences stay separately approved. Preflight first.\n\nMCP: `oxygen_recipes_apply`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"inputs":{"type":"object","description":"Stage inputs keyed by blueprint id.","additionalProperties":true},"slug":{"type":"string","description":"Recipe slug, e.g. 'inbound-led-outbound'.","maxLength":160},"table_refs":{"type":"object","description":"Table bindings keyed by blueprint id then ref.","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_recipes_apply"]}},"/api/cli/recipes/get":{"post":{"operationId":"postRecipesGet","tags":["Recipes"],"summary":"Get Recipe","description":"Returns one recipe: the playbook body (or one section), prerequisites with check commands, credit posture, benchmarks, its kit (ordered Blueprint stages) and the kit's install status here. Read before running; honor every approval gate.\n\nMCP: `oxygen_recipes_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"section":{"type":"string","description":"Return only this body section (e.g. 'The Play', 'Steps'). Frontmatter, kit stages and their install status are always included.","maxLength":60},"slug":{"type":"string","description":"Recipe slug, e.g. 'outbound-pilot-50'.","maxLength":160}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_recipes_get"]}},"/api/cli/recipes/install":{"post":{"operationId":"postRecipesInstall","tags":["Recipes"],"summary":"Install Recipe","description":"Installs a recipe into the workspace wiki as a revisioned playbook page with per-version provenance. Refuses to overwrite a customized copy unless force (edits survive as a revision).\n\nMCP: `oxygen_recipes_install`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"draft":{"type":"boolean","description":"Install as a draft page (drafts never ground AI actions)."},"force":{"type":"boolean","description":"Overwrite a customized copy (edits survive as a revision)."},"slug":{"type":"string","description":"Recipe slug to install, e.g. 'outbound-pilot-50'.","maxLength":160},"wiki_slug":{"type":"string","description":"Target wiki slug (default playbook-<recipe-slug>).","maxLength":160}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_recipes_install"]}},"/api/cli/recipes/preflight":{"post":{"operationId":"postRecipesPreflight","tags":["Recipes"],"summary":"Preflight Recipe Kit","description":"Preflights a recipe's kit (its ordered Blueprint stages) into one forecast: missing integrations/context, collisions, priced upper bounds, and which stages are already installed or active. Read-only, 0 credits. Run before oxygen_recipes_apply.\n\nMCP: `oxygen_recipes_preflight`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"inputs":{"type":"object","description":"Stage inputs keyed by blueprint id, e.g. {\"linkedin-profile-engager-monitor\":{\"profiles\":[...],\"max_credits\":2200}}.","additionalProperties":true},"slug":{"type":"string","description":"Recipe slug, e.g. 'inbound-led-outbound'.","maxLength":160},"table_refs":{"type":"object","description":"Bind a stage's table ref to an existing table id or slug, keyed by blueprint id then ref.","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_recipes_preflight"]}},"/api/cli/runs":{"get":{"operationId":"getRuns","tags":["Runs"],"summary":"List Workspace Runs","description":"Recent workspace runs (provider calls, AI column runs, workflow steps), newest first. One run's full provenance: oxygen_runs_get.\n\nMCP: `oxygen_runs_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum runs to return. Defaults to 50.","minimum":1,"maximum":500}},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"Only this table's runs (id, slug or URL)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_runs_list"]}},"/api/cli/runs/get":{"post":{"operationId":"postRunsGet","tags":["Runs"],"summary":"Get Workspace Run","description":"Returns a workspace run record by id (provider call, AI column, or workflow step) including provenance and steps.\n\nMCP: `oxygen_runs_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"runId":{},"run_id":{"type":"string","description":"Workspace run id, e.g. ox_run_...","minLength":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_runs_get"]}},"/api/cli/search/plan":{"post":{"operationId":"postSearchPlan","tags":["Search"],"summary":"Plan Search Or Scrape","description":"Plans signal, web or source-specific searches; no longer plans people or company search. Use oxygen_companies_search_plan or oxygen_people_search_plan instead. Public LinkedIn reads prefer native cookieless scraper.* operations. Hydrate the selected route before live provider work.\n\nMCP: `oxygen_search_plan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"geography":{"type":"string","description":"Optional geography hint.","maxLength":500},"goal":{"type":"string","description":"Natural-language search or scrape goal.","minLength":1,"maxLength":20000},"kind":{"type":"string","description":"Optional search/scrape route kind.","enum":["signal_search","web_search","web_scrape","local_business_search","source_specific_scrape"]},"known_urls":{"type":"array","description":"Known URLs for scrape routes.","items":{"type":"string"}},"provider_hints":{"type":"array","description":"Optional provider hints.","items":{"type":"string"}},"target_count":{"type":"integer","description":"Optional target row count.","minimum":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_search_plan"]}},"/api/cli/search/run":{"post":{"operationId":"postSearchRun","tags":["Search"],"summary":"Run Search Or Scrape","description":"Previews or enqueues a durable table-backed search/scrape job from an Oxygen search plan for signal, web, scrape, and local-business routes. Live mode requires max_credits. For PEOPLE/contact search use oxygen_people_search_run and for COMPANY search use oxygen_companies_search_run.\n\nMCP: `oxygen_search_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{},"connection_id":{"type":"string","description":"Optional provider connection id."},"cursorPath":{},"cursorRequestKey":{},"cursor_path":{"type":"string","description":"Override route cursor path."},"cursor_request_key":{"type":"string","description":"Override request key that receives next cursor."},"max_credits":{"type":"number","description":"Required credit cap for live runs.","minimum":0},"max_pages":{"type":"integer","description":"Page cap: Blitz people/company/TAM 1,000; Blitz jobs and other routes 100.","minimum":1,"maximum":1000},"mode":{"type":"string","description":"dry_run or live. Defaults to dry_run.","enum":["dry_run","live"]},"request":{"type":"object","description":"Provider request JSON for the selected route.","additionalProperties":true},"route_id":{"type":"string","description":"Route id. Defaults to recommended_route_id."},"rowMapping":{},"row_mapping":{"type":"object","description":"Override route row mapping.","additionalProperties":true},"rowsPath":{},"rows_path":{"type":"string","description":"Override route rows path."},"table":{"type":"string","description":"Target table id or slug.","minLength":1},"upsertKey":{},"upsert_key":{"type":"string","description":"Column key used for upsert mode."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_search_run"]}},"/api/cli/search/runs/{searchRunId}":{"get":{"operationId":"getSearchRunsSearchRunId","tags":["Search"],"summary":"Get Search Run","description":"Gets one durable search/scrape run by id.\n\nMCP: `oxygen_search_runs_get`, `oxygen_search_runs_wait`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"searchRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_search_runs_get","oxygen_search_runs_wait"]}},"/api/cli/search/runs/{searchRunId}/cancel":{"post":{"operationId":"postSearchRunsSearchRunIdCancel","tags":["Search"],"summary":"Cancel Search Run","description":"Requests cancellation for a queued or running search/scrape run.\n\nMCP: `oxygen_search_runs_cancel`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"searchRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_search_runs_cancel"]}},"/api/cli/search/runs/{searchRunId}/items":{"get":{"operationId":"search.runs.items","tags":["Search"],"summary":"Search runs items","description":"Read durable search ingestion items by run id and optional status.\n\nMCP: `oxygen_search_run_items`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"searchRunId","in":"path","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_search_run_items"]}},"/api/cli/search/runs/{searchRunId}/retry-failed":{"post":{"operationId":"postSearchRunsSearchRunIdRetryFailed","tags":["Search"],"summary":"Retry Failed Search Run Items","description":"Requeues failed items for a durable search/scrape run.\n\nMCP: `oxygen_search_runs_retry_failed`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"searchRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_search_runs_retry_failed"]}},"/api/cli/senders":{"get":{"operationId":"getSenders","tags":["Senders"],"summary":"List LinkedIn Sender Accounts","description":"Lists the workspace's connected LinkedIn sender accounts with health status, per-account rate limits, and today's usage. Use before creating sequences or to check account health.\n\nMCP: `oxygen_senders_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"include_usage","in":"query","required":false,"schema":{}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","paused","disconnected","restricted","credentials_required"],"description":"Optional sender-status filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_senders_list"]}},"/api/cli/senders/{id}":{"get":{"operationId":"getSendersId","tags":["Senders"],"summary":"Get LinkedIn Sender Account","description":"Gets one LinkedIn sender account with full limits, daily-reset timezone, and usage. id accepts sender account id, connection id, or Unipile account id.\n\nMCP: `oxygen_senders_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_senders_get"]}},"/api/cli/senders/{id}/checkpoint/resend":{"post":{"operationId":"postSendersIdCheckpointResend","tags":["Senders"],"summary":"Resend LinkedIn Checkpoint","description":"Asks LinkedIn (via Unipile) to resend the security checkpoint notification (2FA / OTP / in-app validation) so the member can read a fresh code, then submit it with oxygen_senders_checkpoint_solve. Account administration — NOT a paid social action. id accepts sender account id, connection id, or Unipile account id.\n\nMCP: `oxygen_senders_checkpoint_resend`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_checkpoint_resend"]}},"/api/cli/senders/{id}/checkpoint/solve":{"post":{"operationId":"postSendersIdCheckpointSolve","tags":["Senders"],"summary":"Solve LinkedIn Checkpoint","description":"Submits the LinkedIn checkpoint code (2FA / OTP / in-app validation) Unipile is waiting on to finish authentication and bring a stuck sender back to active. Account administration — NOT a paid social action, so there is no credit charge or approval gate. id accepts sender account id, connection id, or Unipile account id; code is the verification code LinkedIn sent.\n\nMCP: `oxygen_senders_checkpoint_solve`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","description":"The verification code LinkedIn sent (2FA / OTP / in-app validation)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_checkpoint_solve"]}},"/api/cli/senders/{id}/disconnect":{"post":{"operationId":"postSendersIdDisconnect","tags":["Senders"],"summary":"Disconnect LinkedIn Sender Account","description":"Disconnects a LinkedIn sender account so it stops sending and reading immediately. Reconnect later with oxygen_senders_connect (reconnect_connection_id). id accepts sender account id, connection id, or Unipile account id.\n\nMCP: `oxygen_senders_disconnect`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_senders_disconnect"]}},"/api/cli/senders/{id}/health":{"get":{"operationId":"getSendersIdHealth","tags":["Senders"],"summary":"LinkedIn Sender Health","description":"One-call health snapshot for a LinkedIn sender: tenant + connection status, the latest account error reason, any open security checkpoint, today's usage, the warm-up ramp, when the daily quota resets, and inbox sync (last sync, latest failure, back-off). Read-only — a tenant read, no provider call, no credits. id accepts sender account id, connection id, or Unipile account id.\n\nMCP: `oxygen_senders_health`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_senders_health"]}},"/api/cli/senders/{id}/inbox-scope":{"get":{"operationId":"getSendersIdInboxScope","tags":["Senders"],"summary":"Get LinkedIn Inbox Scope","description":"Reads whether one LinkedIn sender syncs only conversations started through OXYGEN or the entire LinkedIn inbox. No provider call and no credits.\n\nMCP: `oxygen_senders_inbox_scope_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_senders_inbox_scope_get"]},"patch":{"operationId":"patchSendersIdInboxScope","tags":["Senders"],"summary":"Set LinkedIn Inbox Scope","description":"Changes LinkedIn inbox privacy for one sender. oxygen_initiated stops ingesting and hides unrelated chats; all explicitly opts into the full inbox. This internal, zero-credit change does not call the provider or send a message. Existing stored messages are retained, not deleted.\n\nMCP: `oxygen_senders_inbox_scope_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"inbox_sync_scope":{},"scope":{"type":"string","enum":["oxygen_initiated","all"],"description":"oxygen_initiated or all."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_inbox_scope_set"]}},"/api/cli/senders/{id}/limits":{"get":{"operationId":"getSendersIdLimits","tags":["Senders"],"summary":"Get LinkedIn Account Limits","description":"Reads the per-account limits envelope: current effective limits, the org's overrides, working hours, the warm-up ramp state (whether the account is still warming and today's effective invite/message caps), plus defaults, hard maximums and caution levels. Read this before oxygen_senders_limits_set so proposed values are not silently clamped. id accepts sender account id, connection id, or Unipile account id.\n\nMCP: `oxygen_senders_limits_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_senders_limits_get"]},"patch":{"operationId":"senders.limits.set","tags":["Senders"],"summary":"Set LinkedIn Account Limits","description":"Adjust per-account action limits and working hours. LinkedIn actions only run inside the account's working hours (default 07:00-22:00 every day, in the account's timezone); work due outside them is deferred to the next window, not failed. Set them with --timezone, --working-days, --working-hours-start and --working-hours-end; flags you omit keep their current value. A sequence's sending schedule (sequences update --schedule-*, or --linkedin-* for LinkedIn alone) can narrow the window for its LinkedIn steps, never widen it; email steps follow the sequence's email send window instead. Every limit flag shows its default and hard maximum; values above the maximum are clamped, and higher caps raise the risk of a LinkedIn restriction. Each action has its own cap (InMails per day and per rolling 30 days, profile views, profile lookups, endorsements, invitation withdrawals, posts), and every send except posts also counts toward --total-actions-per-day. Daily send caps run at half on Saturday and Sunday in the account's timezone unless --weekend-full-volume is set. A withdrawn invitation cannot be re-sent to the same person for 21 days. Own-feed posts and your own Unibox replies ignore working hours. A refused action names its reason (outside_working_hours defers it; linkedin_rate_limited names the limit and resets_at). Caps saved before 25 Sep 2026 above 40 messages, 20 comments or 200 total actions were lowered to those levels once on 2 Oct 2026 (old values in sender metadata linkedin_limit_caution_2026_10); limits you save now are kept as set. Raising caps to answer a post's commenters: read `oxygen skills get oxygen-sequencer --file references/linkedin.md` first. Changing limits is free. <id> accepts a sender account id, connection id, or Unipile account id.\n\nMCP: `oxygen_senders_limits_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"publishing_approval":{"type":"object","description":"Admin sets initial owner; only owner manages delegates/policy. Free.","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["workspace","owner"]},"owner_user_id":{"type":"string","description":"Workspace user UUID; required for owner mode."},"delegate_user_ids":{"type":"array","items":{"type":"string"},"maxItems":50,"description":"Workspace user UUIDs."}},"required":["mode"]},"limits":{"type":"object","description":"Per-account caps for sends and reads. Values above the maximum are clamped server-side.","additionalProperties":false,"properties":{"invites_per_day":{"type":"integer","minimum":0,"maximum":30,"x-clamp":true,"description":"Max 30 (default 20)."},"invites_per_week":{"type":"integer","minimum":0,"maximum":150,"x-clamp":true,"description":"Max 150 (default 100)."},"messages_per_day":{"type":"integer","minimum":0,"maximum":200,"x-clamp":true,"description":"Max 200 (default 40). Above 40 raises the risk of a LinkedIn restriction."},"inmails_per_day":{"type":"integer","minimum":0,"maximum":25,"x-clamp":true,"description":"Max 25 (default 10)."},"inmails_per_month":{"type":"integer","minimum":0,"maximum":800,"x-clamp":true,"description":"Max 800 (default 400). Rolling 30 days."},"profile_views_per_day":{"type":"integer","minimum":0,"maximum":100,"x-clamp":true,"description":"Max 100 (default 50)."},"profile_lookups_per_day":{"type":"integer","minimum":0,"maximum":100,"x-clamp":true,"description":"Max 100 (default 80). Invisible profile/company lookups."},"endorsements_per_day":{"type":"integer","minimum":0,"maximum":10,"x-clamp":true,"description":"Max 10 (default 5)."},"withdrawals_per_day":{"type":"integer","minimum":0,"maximum":20,"x-clamp":true,"description":"Max 20 (default 10). Sent-invite withdrawals."},"posts_per_day":{"type":"integer","minimum":0,"maximum":25,"x-clamp":true,"description":"Max 25 (default 10). Own-feed posts."},"follows_per_day":{"type":"integer","minimum":0,"maximum":50,"x-clamp":true,"description":"Max 50 (default 20)."},"likes_per_day":{"type":"integer","minimum":0,"maximum":50,"x-clamp":true,"description":"Max 50 (default 20)."},"comments_per_day":{"type":"integer","minimum":0,"maximum":200,"x-clamp":true,"description":"Max 200 (default 5). Above 20 raises the risk of a LinkedIn restriction."},"total_actions_per_day":{"type":"integer","minimum":0,"maximum":500,"x-clamp":true,"description":"Max 500 (default 150). All sends except posts. Above 200 raises the risk of a LinkedIn restriction."},"relations_reads_per_day":{"type":"integer","minimum":0,"maximum":100,"x-clamp":true,"description":"Max 100 (default 20). Connection-list reads."},"messages_reads_per_day":{"type":"integer","minimum":0,"maximum":600,"x-clamp":true,"description":"Max 600 (default 200). Message-history reads."},"searches_per_day":{"type":"integer","minimum":0,"maximum":100,"x-clamp":true,"description":"Max 100 (default 20)."},"sales_nav_search_results_per_day":{"type":"integer","minimum":0,"maximum":1000,"x-clamp":true,"description":"Max 1000 (default 1000). Result rows."},"api_reads_per_day":{"type":"integer","minimum":0,"maximum":1000,"x-clamp":true,"description":"Max 1000 (default 200). Other API reads."},"total_reads_per_day":{"type":"integer","minimum":0,"maximum":2000,"x-clamp":true,"description":"Max 2000 (default 1000). All reads."},"min_action_spacing_seconds":{"type":"integer","minimum":0,"maximum":3600,"x-clamp":true,"description":"Max 3600 (default 300). Floor; campaigns spread each day's limit over working hours (20 invites in 07:00-22:00: 30-45 min apart)."},"action_spacing_jitter_seconds":{"type":"integer","minimum":0,"maximum":1800,"x-clamp":true,"description":"Max 1800 (default 300)."},"interactive_min_spacing_seconds":{"type":"integer","minimum":0,"maximum":3600,"x-clamp":true,"description":"Max 3600 (default 1). Human Unibox send spacing."},"interactive_spacing_jitter_seconds":{"type":"integer","minimum":0,"maximum":1800,"x-clamp":true,"description":"Max 1800 (default 0). Jitter on that spacing."},"interactive_sends_per_hour":{"type":"integer","minimum":0,"maximum":300,"x-clamp":true,"description":"Max 300 (default 200). Hourly human send cap."},"relations_ingest_reads_per_day":{"type":"integer","minimum":0,"maximum":100,"x-clamp":true,"description":"Max 100 (default 15). Background connection/follower list reads."},"api_ingest_reads_per_day":{"type":"integer","minimum":0,"maximum":200,"x-clamp":true,"description":"Max 200 (default 20). Background engagement and post-metric reads."},"messages_ingest_reads_per_day":{"type":"integer","minimum":0,"maximum":200,"x-clamp":true,"description":"Max 200 (default 10). Background message-history backfill."},"network_backfill_reads_per_day":{"type":"integer","minimum":0,"maximum":100,"x-clamp":true,"description":"Max 100 (default 40). Network capture, first walk."},"network_delta_reads_per_day":{"type":"integer","minimum":0,"maximum":20,"x-clamp":true,"description":"Max 20 (default 4). Network capture, once walked."}}},"working_hours":{"type":"object","description":"When LinkedIn actions may run (default 07:00-22:00 daily); campaigns spread each day's limit across them, starting at a different time each day. Work outside waits. Omitted fields keep their value.","additionalProperties":false,"properties":{"timezone":{"type":"string","description":"IANA zone for hours and daily reset, e.g. Europe/Berlin."},"days":{"type":"array","items":{"type":"integer","minimum":1,"maximum":7},"description":"ISO weekdays, 1=Mon."},"start":{"type":"string","description":"HH:MM, e.g. 09:00."},"end":{"type":"string","description":"HH:MM, after start."}}},"warmup":{"type":"object","description":"Warm-up ramp override for this account. Warm-up gradually raises invite + message caps to full over ~2 weeks and is auto-enabled at first connect (pre-existing accounts are treated as already warm). Use { enabled: true } to start/restart the ramp now, { enabled: false } to disable it (account uses its full configured caps), or { start_date } to anchor the ramp to a specific day.","additionalProperties":false,"properties":{"enabled":{"type":"boolean","description":"true = start/restart the ramp at day 0; false = disable warm-up (account becomes warm)."},"start_date":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"ISO date (e.g. 2026-01-31) to anchor the ramp start. A past date credits prior warming and advances the ramp day; a future date holds at day 0 until it arrives. null disables warm-up."}}},"read_warmup":{"type":"boolean","description":"Network-capture read ramp: false runs full read budget now; true restarts it from today."},"warmup_preset":{"type":"string","enum":["conservative","standard","fast"],"description":"Warm-up ramp: ~3 weeks, ~2 (default), ~1 for an aged account."},"randomize_daily_caps":{"type":"boolean","description":"Vary each day's caps a little so volume is not identical daily."},"weekend_full_volume":{"type":"boolean","description":"Send caps halve on Saturday and Sunday in the account's timezone. true keeps full volume; false restores the halving."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_limits_set"]}},"/api/cli/senders/{id}/proxy-country":{"patch":{"operationId":"patchSendersIdProxyCountry","tags":["Senders"],"summary":"Move LinkedIn Proxy Country","description":"Moves a LinkedIn sender's proxy to another country without reconnecting (zero credits). If none is free there, the sender stays paused and each sync retries.\n\nMCP: `oxygen_senders_proxy_country_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"country":{"type":"string","description":"ISO alpha-2 country the owner logs in from."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_proxy_country_set"]}},"/api/cli/senders/{id}/tags":{"post":{"operationId":"postSendersIdTags","tags":["Senders"],"summary":"Tag Sender Account","description":"Replaces a LinkedIn/WhatsApp sender account's workspace tags (Tags primitive; see oxygen_tags_list). Whole-set: pass the full list, [] clears.\n\nMCP: `oxygen_senders_tag`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"The full workspace tag list to set ([] clears)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_tag"]}},"/api/cli/senders/checkpoints":{"get":{"operationId":"senders.checkpoints","tags":["Senders"],"summary":"Senders checkpoints","description":"Read connected sender authentication checkpoints that need human completion.\n\nMCP: `oxygen_sender_checkpoints`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sender_checkpoints"]}},"/api/cli/senders/connect":{"post":{"operationId":"postSendersConnect","tags":["Senders"],"summary":"Connect LinkedIn Account","description":"Creates 1-25 10-minute LinkedIn authorizations. Prices: oxygen_billing_commitments view=connection-prices. OXYGEN-started chats sync by default. cookie_auth/custom_proxy: OXYGEN never receives those secrets. sales_nav needs a subscription; reconnect keeps inbox scope.\n\nMCP: `oxygen_senders_connect`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"acknowledge_linkedin_risk":{"type":"boolean","description":"Deprecated; not required."},"cookie_auth":{"type":"boolean","description":"Offer cookie login on the hosted page."},"count":{"type":"integer","minimum":1,"maximum":25,"description":"Mint N hosted-auth links in one call for bulk onboarding (default 1). Every link uses the same country; use separate calls for different login countries. Ignored when reconnecting."},"country":{"type":"string","description":"Required for new accounts: ISO 3166-1 alpha-2 code for the account owner's normal LinkedIn login country, not the campaign target; unsupported ones are refused."},"custom_proxy":{"type":"boolean","description":"Allow proxy entry on the hosted page."},"established":{"type":"boolean","description":"Established profile: skip the ~2-week warm-up new accounts get."},"inboxSyncScope":{},"inbox_sync_scope":{},"n":{},"owner_consent":{"type":"boolean","description":"Required when count > 1: each account owner connects their own account."},"reconnectConnectionId":{},"reconnect_connection_id":{"type":"string","description":"Control-plane connection id to reconnect instead of creating a new account."},"sales_nav":{"type":"boolean","description":"Request Classic + Sales Navigator access during hosted authentication."},"share_link":{"type":"boolean","description":"Share one link with its account owner."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_connect"]}},"/api/cli/senders/profiles":{"get":{"operationId":"getSendersProfiles","tags":["Senders"],"summary":"List Sender Profiles","description":"List people’s LinkedIn/WhatsApp/inbox identities and channel counts. first_name/last_name are required for orders; avatar_durable controls whether orders use the photo. Filter by status/tag.\n\nMCP: `oxygen_senders_profiles_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","paused","archived"],"description":"Optional status filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_senders_profiles_list"]},"post":{"operationId":"postSendersProfiles","tags":["Senders"],"summary":"Create Sender Profile","description":"Create a person. from_sender_account_id seeds name/photo and attaches an account; otherwise name is required. Attach inboxes via mailbox_ids and DM accounts via sender_account_ids. Accounts have one profile. Ordered inboxes keep first/last names. May return avatar_warning.\n\nMCP: `oxygen_senders_profiles_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"avatarFromLinkedin":{},"avatarUploadKey":{},"avatarUrl":{},"avatar_from_linkedin":{"type":"boolean","description":"Mirror the attached LinkedIn photo into Oxygen storage (durable). Default with from_sender_account_id."},"avatar_upload_key":{"type":"string","description":"storage_key from the avatar upload flow; re-verified server-side."},"avatar_url":{"type":"string","description":"Photo URL, or \"\" for none. Only Oxygen-hosted photos survive the vendor's later fetch."},"first_name":{"type":"string","description":"Given name stamped on ordered mailboxes."},"from_sender_account_id":{"type":"string","description":"LinkedIn/WhatsApp sender id to seed name+avatar from and attach."},"last_name":{"type":"string","description":"Family name stamped on ordered mailboxes."},"mailboxIds":{},"mailbox_ids":{"type":"array","items":{"type":"string"},"description":"Email mailbox ids to attach."},"name":{"type":"string","description":"Display name; optional when from_sender_account_id is set."},"senderAccountIds":{},"sender_account_ids":{"type":"array","items":{"type":"string"},"description":"LinkedIn/WhatsApp sender ids to attach."},"status":{"type":"string","enum":["active","paused","archived"],"description":"Initial status (default active)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_profiles_create"]}},"/api/cli/senders/profiles/{id}":{"get":{"operationId":"getSendersProfilesId","tags":["Senders"],"summary":"Get Sender Profile","description":"Read one person’s LinkedIn/WhatsApp senders and inboxes.\n\nMCP: `oxygen_senders_profiles_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_senders_profiles_get"]},"patch":{"operationId":"patchSendersProfilesId","tags":["Senders"],"summary":"Update Sender Profile","description":"Edit a person and membership. Attach: sender_account_ids/mailbox_ids. Detach: detach_sender_account_ids/detach_mailbox_ids. May return avatar_warning.\n\nMCP: `oxygen_senders_profiles_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"avatarFromLinkedin":{},"avatarUploadKey":{},"avatarUrl":{},"avatar_from_linkedin":{"type":"boolean","description":"Re-mirror the attached LinkedIn photo into Oxygen storage (durable). 409 without a LinkedIn account."},"avatar_upload_key":{"type":"string","description":"storage_key from the avatar upload flow; re-verified server-side."},"avatar_url":{"type":"string","description":"Photo URL, or \"\" to clear. Only Oxygen-hosted photos stay durable."},"detachMailboxIds":{},"detachSenderAccountIds":{},"detach_mailbox_ids":{"type":"array","items":{"type":"string"},"description":"Inbox ids to detach."},"detach_sender_account_ids":{"type":"array","items":{"type":"string"},"description":"Sender ids to detach."},"first_name":{"type":"string","description":"Given name stamped on ordered mailboxes."},"last_name":{"type":"string","description":"Family name stamped on ordered mailboxes."},"mailboxIds":{},"mailbox_ids":{"type":"array","items":{"type":"string"},"description":"Inbox ids to attach."},"name":{"type":"string","description":"New display name."},"senderAccountIds":{},"sender_account_ids":{"type":"array","items":{"type":"string"},"description":"Sender ids to attach."},"status":{"type":"string","enum":["active","paused","archived"],"description":"New status."},"voice_page":{"type":"string","description":"Voice page slug to propose as this sender's voice; \"none\" unbinds."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_profiles_update"]},"delete":{"operationId":"deleteSendersProfilesId","tags":["Senders"],"summary":"Delete Sender Profile","description":"Deletes a sender profile. Its accounts detach (return to the unassigned pool); they are never deleted.\n\nMCP: `oxygen_senders_profiles_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_senders_profiles_delete"]}},"/api/cli/senders/profiles/{id}/tags":{"post":{"operationId":"postSendersProfilesIdTags","tags":["Senders"],"summary":"Tag Sender Profile","description":"Replaces a sender profile's workspace tags (Tags primitive; see oxygen_tags_list). Whole-set: pass the full list, [] clears. Pools the whole sending identity behind one campaign tag; member accounts keep their own.\n\nMCP: `oxygen_senders_profiles_tag`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"The full workspace tag list to set ([] clears)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_profiles_tag"]}},"/api/cli/senders/sync":{"post":{"operationId":"postSendersSync","tags":["Senders"],"summary":"Sync LinkedIn Accounts","description":"Refreshes account health/status from Unipile for all (or one) connected LinkedIn accounts.\n\nMCP: `oxygen_senders_sync`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{},"connection_id":{"type":"string","description":"Optional control-plane connection id to sync a single account instead of all."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_senders_sync"]}},"/api/cli/sequencer/brand-kit":{"get":{"operationId":"getSequencerBrandKit","tags":["Sequencer"],"summary":"Sending Domains","description":"Sending domains send bulk email (newsletters, onboarding) through Amazon SES from a verified domain, not a mailbox. action=list (default); add a domain or subdomain of one in oxygen_domains_list; verify checks DKIM and MAIL FROM; pause (paused=false resumes, only once verified); update; release removes it (refused while emails wait). Publish dns_records with oxygen_domains_dns_plan sending_domain. brand_kit_get/brand_kit_set: the newsletter brand kit; set changes only fields passed, \"\" clears; a newsletter starts only once postal_address is set. 0 credits.\n\nMCP: `oxygen_domains_sending`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_sending"]},"patch":{"operationId":"patchSequencerBrandKit","tags":["Sequencer"],"summary":"Sending Domains","description":"Sending domains send bulk email (newsletters, onboarding) through Amazon SES from a verified domain, not a mailbox. action=list (default); add a domain or subdomain of one in oxygen_domains_list; verify checks DKIM and MAIL FROM; pause (paused=false resumes, only once verified); update; release removes it (refused while emails wait). Publish dns_records with oxygen_domains_dns_plan sending_domain. brand_kit_get/brand_kit_set: the newsletter brand kit; set changes only fields passed, \"\" clears; a newsletter starts only once postal_address is set. 0 credits.\n\nMCP: `oxygen_domains_sending`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"background_color":{"type":"string","description":"brand_kit_set colours: #rrggbb."},"button_color":{"type":"string"},"button_text_color":{"type":"string"},"company_name":{"type":"string"},"container_width":{"oneOf":[{"type":"integer","minimum":480,"maximum":800},{"type":"null"}]},"content_background_color":{"type":"string"},"font_family":{"type":"string","enum":["system","georgia","arial","helvetica","verdana",""]},"link_color":{"type":"string"},"logo_url":{"type":"string","description":"brand_kit_set: https URL."},"logo_width":{"oneOf":[{"type":"integer","minimum":40,"maximum":600},{"type":"null"}]},"postal_address":{"type":"string","maxLength":500,"description":"Footer of every newsletter."},"preference_page_description":{"type":"string"},"preference_page_title":{"type":"string"},"social_links":{"type":"array","items":{"type":"object","properties":{"network":{"type":"string","enum":["website","linkedin","x","facebook","instagram","youtube","tiktok","github"]},"url":{"type":"string"}},"additionalProperties":false,"required":["network","url"]}},"text_color":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_sending"]}},"/api/cli/sequencer/hubspot-list-import":{"get":{"operationId":"getSequencerHubspotListImport","tags":["Sequencer"],"summary":"List HubSpot Sequence Segments","description":"List saved HubSpot contact and company segments plus readable identity fields without reading members or writing. Pass separate lead/contact-DNC/company-DNC ids to the import tool.\n\nMCP: `oxygen_sequences_hubspot_lists`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_hubspot_lists"]},"post":{"operationId":"postSequencerHubspotListImport","tags":["Sequencer"],"summary":"Configure HubSpot List Import","description":"Preview or arm recurring HubSpot-list enrollment. DNC completes first; draft/paused recipients stay pending. Live requires approval and the dry-run fingerprint.\n\nMCP: `oxygen_sequences_hubspot_list_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"companyDncListId":{},"company_dnc_list_id":{"type":"string","description":"Optional HubSpot company-list id for all-channel company DNC."},"company_domain_property":{"type":"string","description":"Company-list domain property; defaults to domain."},"company_linkedin_property":{"type":"string","description":"Optional company-list LinkedIn URL property."},"connectionId":{},"connection_id":{"type":"string","description":"HubSpot connection every cycle reads; defaults to the workspace default."},"contactProperties":{},"contact_company_domain_property":{"type":"string","description":"Optional explicit contact company-domain property copied to lead rows."},"contact_company_linkedin_property":{"type":"string","description":"Optional explicit contact company LinkedIn property copied to lead rows."},"contact_linkedin_property":{"type":"string","description":"Optional contact LinkedIn profile property internal name."},"contact_properties":{"type":"array","maxItems":50,"items":{"type":"string"}},"cron":{"type":"string"},"dncListId":{},"dnc_list_id":{"type":"string"},"exclude_contacted":{"type":"boolean","description":"Default true; skip leads whose LinkedIn identity is still enrolled in another active sequence (stored only when this sequence has LinkedIn steps)."},"idempotencyKey":{},"idempotency_key":{"type":"string"},"leadListId":{},"lead_list_id":{"type":"string"},"live":{},"max_credits":{"type":"number","exclusiveMinimum":0},"max_records_per_list":{"type":"integer","minimum":1,"maximum":5000},"mode":{"type":"string","enum":["dry_run","live"],"description":"Default dry_run; live arms sync."},"reviewedFingerprint":{},"reviewed_fingerprint":{"type":"string","description":"Dry-run fingerprint; required for live."},"sequence":{"type":"string"},"sequenceId":{},"sequence_id":{},"timezone":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_hubspot_list_import"]}},"/api/cli/sequencer/hubspot-sync":{"get":{"operationId":"getSequencerHubspotSync","tags":["Sequencer"],"summary":"Get Sequencer HubSpot Event Sync","description":"Reads the workspace-wide HubSpot projection across every Sequence. Returns the connected portal and live schema, optional latest-event fields, native email/LinkedIn timeline coverage, lead-status mappings, and health of the managed activity/reply Workflow pair. No HubSpot record is changed.\n\nMCP: `oxygen_sequences_hubspot_sync_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_hubspot_sync_get"]},"post":{"operationId":"postSequencerHubspotSync","tags":["Sequencer"],"summary":"Configure Sequencer HubSpot Event Sync","description":"Preview or save the workspace-wide HubSpot activity and lead-status projection for every Sequence. Dry-run first; live enable requires approval and installs two inspectable Workflows.\n\nMCP: `oxygen_sequences_hubspot_sync_configure`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"armed":{"type":"boolean"},"config":{},"live":{},"mode":{"type":"string","enum":["dry_run","live"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_hubspot_sync_configure"]}},"/api/cli/sequencer/reply-workflows":{"get":{"operationId":"getSequencerReplyWorkflows","tags":["Sequencer"],"summary":"List Legacy Sequencer Workflow Presets","description":"Compatibility surface for the two old sequencer presets: internal CRM lead-stage routing and positive-reply Microsoft Teams notifications. New sequence-connected automations are ordinary Workflows, created and managed with the oxygen_workflows_* tools. Returns ordinary workflow links. HubSpot sequence-event mapping has its own oxygen_sequences_hubspot_sync_get/configure tools.\n\nMCP: `oxygen_sequences_workflows_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_workflows_list"]},"post":{"operationId":"postSequencerReplyWorkflows","tags":["Sequencer"],"summary":"Configure Sequencer Reply Workflow","description":"Compatibility surface that previews or saves one old sequencer preset. New sequence-connected automations are ordinary Workflows. Call mode=dry_run first. Arming requires mode=live, approved=true, and a positive per-delivery max_credits ceiling. The Teams preset additionally requires an exact connection_id/team_id/channel_id and max_credits>=0.02; Teams uses customer OAuth, so the estimate covers only two Oxygen automation checkpoints. Internal CRM routing calls no external provider and currently estimates 0 credits, but still needs revision-bound standing authorization.\n\nMCP: `oxygen_sequences_workflows_configure`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required true to arm any autonomous reply workflow."},"armed":{"type":"boolean","description":"Arm or disarm this workflow."},"config":{"type":"object","additionalProperties":true,"description":"Editable compatibility config. CRM: enabled_channels, sequence_ids, assertable_statuses, engaged_statuses, meeting_statuses. Teams: connection_id, team_id, channel_id, enabled_channels, sequence_ids, positive_statuses, message_template, max_credits."},"live":{},"max_credits":{"type":"number","minimum":0.01,"description":"Hard per-delivery ceiling. The legacy Teams preset requires at least 0.02 credits."},"mode":{"type":"string","enum":["dry_run","live"],"description":"Defaults to dry_run. Use live only after reviewing the preview."},"template_id":{"type":"string","enum":["crm-lead-stage-router","sequencer-positive-reply-teams"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_workflows_configure"]}},"/api/cli/sequencer/sending-domains":{"get":{"operationId":"getSequencerSendingDomains","tags":["Sequencer"],"summary":"Sending Domains","description":"Sending domains send bulk email (newsletters, onboarding) through Amazon SES from a verified domain, not a mailbox. action=list (default); add a domain or subdomain of one in oxygen_domains_list; verify checks DKIM and MAIL FROM; pause (paused=false resumes, only once verified); update; release removes it (refused while emails wait). Publish dns_records with oxygen_domains_dns_plan sending_domain. brand_kit_get/brand_kit_set: the newsletter brand kit; set changes only fields passed, \"\" clears; a newsletter starts only once postal_address is set. 0 credits.\n\nMCP: `oxygen_domains_sending`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_sending"]},"post":{"operationId":"postSequencerSendingDomains","tags":["Sequencer"],"summary":"Sending Domains","description":"Sending domains send bulk email (newsletters, onboarding) through Amazon SES from a verified domain, not a mailbox. action=list (default); add a domain or subdomain of one in oxygen_domains_list; verify checks DKIM and MAIL FROM; pause (paused=false resumes, only once verified); update; release removes it (refused while emails wait). Publish dns_records with oxygen_domains_dns_plan sending_domain. brand_kit_get/brand_kit_set: the newsletter brand kit; set changes only fields passed, \"\" clears; a newsletter starts only once postal_address is set. 0 credits.\n\nMCP: `oxygen_domains_sending`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"allowed_from_addresses":{"type":"array","items":{"type":"string"},"description":"add/update: From addresses on it; [] clears."},"daily_ceiling":{"type":"integer","minimum":0,"description":"add/update: emails per day (default 1000)."},"email_domain":{"type":"string","description":"add: its domain from oxygen_domains_list (id or name)."},"identity":{"type":"string","description":"add: the domain, e.g. news.acme.com."},"mail_from_domain":{"type":"string","description":"add: default mail.<identity>."},"reply_to_mailbox_id":{"type":"string","description":"add/update: mailbox id or address for replies; \"\" clears."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_sending"]}},"/api/cli/sequencer/sending-domains/{id}":{"patch":{"operationId":"patchSequencerSendingDomainsId","tags":["Sequencer"],"summary":"Sending Domains","description":"Sending domains send bulk email (newsletters, onboarding) through Amazon SES from a verified domain, not a mailbox. action=list (default); add a domain or subdomain of one in oxygen_domains_list; verify checks DKIM and MAIL FROM; pause (paused=false resumes, only once verified); update; release removes it (refused while emails wait). Publish dns_records with oxygen_domains_dns_plan sending_domain. brand_kit_get/brand_kit_set: the newsletter brand kit; set changes only fields passed, \"\" clears; a newsletter starts only once postal_address is set. 0 credits.\n\nMCP: `oxygen_domains_sending`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"allowed_from_addresses":{"type":"array","items":{"type":"string"},"description":"add/update: From addresses on it; [] clears."},"daily_ceiling":{"type":"integer","minimum":0,"description":"add/update: emails per day (default 1000)."},"reply_to_mailbox_id":{"type":"string","description":"add/update: mailbox id or address for replies; \"\" clears."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_sending"]}},"/api/cli/sequencer/sending-domains/{id}/pause":{"post":{"operationId":"postSequencerSendingDomainsIdPause","tags":["Sequencer"],"summary":"Sending Domains","description":"Sending domains send bulk email (newsletters, onboarding) through Amazon SES from a verified domain, not a mailbox. action=list (default); add a domain or subdomain of one in oxygen_domains_list; verify checks DKIM and MAIL FROM; pause (paused=false resumes, only once verified); update; release removes it (refused while emails wait). Publish dns_records with oxygen_domains_dns_plan sending_domain. brand_kit_get/brand_kit_set: the newsletter brand kit; set changes only fields passed, \"\" clears; a newsletter starts only once postal_address is set. 0 credits.\n\nMCP: `oxygen_domains_sending`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"paused":{"type":"boolean","description":"pause: false resumes (default true)."},"reason":{"type":"string","description":"pause: shown on the account."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_sending"]}},"/api/cli/sequencer/sending-domains/{id}/release":{"post":{"operationId":"postSequencerSendingDomainsIdRelease","tags":["Sequencer"],"summary":"Sending Domains","description":"Sending domains send bulk email (newsletters, onboarding) through Amazon SES from a verified domain, not a mailbox. action=list (default); add a domain or subdomain of one in oxygen_domains_list; verify checks DKIM and MAIL FROM; pause (paused=false resumes, only once verified); update; release removes it (refused while emails wait). Publish dns_records with oxygen_domains_dns_plan sending_domain. brand_kit_get/brand_kit_set: the newsletter brand kit; set changes only fields passed, \"\" clears; a newsletter starts only once postal_address is set. 0 credits.\n\nMCP: `oxygen_domains_sending`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_sending"]}},"/api/cli/sequencer/sending-domains/{id}/verify":{"post":{"operationId":"postSequencerSendingDomainsIdVerify","tags":["Sequencer"],"summary":"Sending Domains","description":"Sending domains send bulk email (newsletters, onboarding) through Amazon SES from a verified domain, not a mailbox. action=list (default); add a domain or subdomain of one in oxygen_domains_list; verify checks DKIM and MAIL FROM; pause (paused=false resumes, only once verified); update; release removes it (refused while emails wait). Publish dns_records with oxygen_domains_dns_plan sending_domain. brand_kit_get/brand_kit_set: the newsletter brand kit; set changes only fields passed, \"\" clears; a newsletter starts only once postal_address is set. 0 credits.\n\nMCP: `oxygen_domains_sending`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_domains_sending"]}},"/api/cli/sequences":{"get":{"operationId":"getSequences","tags":["Sequences"],"summary":"List Sequences","description":"Complete compact campaign roster and fleet counts. view=full adds settings and detailed health.\n\nMCP: `oxygen_sequences_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["summary","full"],"description":"CLI/MCP default summary; full details."}},{"name":"omit","in":"query","required":false,"schema":{"type":"string","description":"warnings: skip warnings and their extra reads."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_list"]},"post":{"operationId":"postSequences","tags":["Sequences"],"summary":"Create Sequence","description":"Create an inert multichannel Sequence; Start needs approval. activation_id binds authored LinkedIn steps to its source Table, without AI. LinkedIn/WhatsApp need senders. Default sending_schedule: email weekdays 09:00-17:00 UTC. include_unsubscribe is shared; channel windows/parts: oxygen_sequences_update.\n\nMCP: `oxygen_sequences_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"activation_id":{"type":"string","minLength":36,"maxLength":36},"activation_revision":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Current revision; first create checks it."},"channels":{"type":"array","items":{"type":"string","enum":["linkedin","email","whatsapp","call","crm"]},"description":"Omit to derive channels from steps."},"definition":{"type":"object","description":"Multichannel SequenceDefinition: {steps:[...]}.","properties":{"steps":{"type":"array","items":{"type":"object","description":"Interpolation, spintax, conditionals. CRM: exact-identity upserts/links and property mappings. Sender: {{sender_first_name}}, {{sender_last_name}}, {{sender_full_name}}; email also {{sender_email}}.","properties":{"channel":{"type":"string","enum":["linkedin","email","whatsapp","call","crm"],"description":"Defaults from kind."},"id":{"type":"string","description":"Branch target id; auto if omitted."},"kind":{"type":"string","enum":["visit_profile","invite","wait_for_connection","message","inmail","follow","like_post","comment_post","withdraw_invite","email_send","email_enroll","email_move","email_stop","whatsapp_message","call_task","crm_task","wait","wait_for_signal","branch","stop"]},"note_template":{"type":"string","description":"invite: optional connection note."},"note":{"type":"string","description":"call_task talking points; never sent."},"priority":{"type":"integer","description":"call_task: queue ordering, higher first."},"provider":{"type":"string","enum":["hubspot"]},"connection_id":{"type":"string","description":"crm_task connection; omit for the active default."},"property_mappings":{"type":"object","additionalProperties":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","enum":["literal"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},"required":["source","value"]},{"type":"object","properties":{"source":{"type":"string","enum":["row"]},"key":{"type":"string","description":"Enrollment row_values key."}},"required":["source","key"]},{"type":"object","properties":{"source":{"type":"string","enum":["template"]},"template":{"type":"string"}},"required":["source","template"]},{"type":"object","properties":{"source":{"type":"string","enum":["relative_time"]},"offset_minutes":{"type":"integer","minimum":0,"maximum":525600}},"required":["source","offset_minutes"]}],"description":"CRM source: literal, row field, template, or timestamp relative to materialization."},"description":"crm_task property name → value source; HubSpot requires hs_timestamp."},"record_mappings":{"type":"object","additionalProperties":{"type":"object","additionalProperties":true,"description":"Requires object_type and identities[{kind: provider_id|email|domain|linkedin_url|exact, property?, value}]. Optional property_mappings, on_missing fail|create, on_match reuse|update. Name-only matching is forbidden."},"description":"crm_task named person/account/deal bindings."},"record_links":{"type":"array","maxItems":20,"items":{"type":"object","properties":{"from_record":{"type":"string"},"to_record":{"type":"string"},"association_type_id":{"type":"integer","minimum":1},"association_category":{"type":"string","enum":["HUBSPOT_DEFINED","USER_DEFINED"]}},"required":["from_record","to_record"]},"description":"crm_task links between named records."},"associations":{"type":"array","maxItems":20,"items":{"type":"object","properties":{"record_ref":{"type":"string"},"object_type":{"type":"string"},"object_id":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","enum":["literal"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},"required":["source","value"]},{"type":"object","properties":{"source":{"type":"string","enum":["row"]},"key":{"type":"string","description":"Enrollment row_values key."}},"required":["source","key"]},{"type":"object","properties":{"source":{"type":"string","enum":["template"]},"template":{"type":"string"}},"required":["source","template"]},{"type":"object","properties":{"source":{"type":"string","enum":["relative_time"]},"offset_minutes":{"type":"integer","minimum":0,"maximum":525600}},"required":["source","offset_minutes"]}],"description":"CRM source: literal, row field, template, or timestamp relative to materialization."},"association_type_id":{"type":"integer","minimum":1},"association_category":{"type":"string","enum":["HUBSPOT_DEFINED","USER_DEFINED"]}}},"description":"crm_task task targets: exactly one record_ref or object_id; record_ref infers object_type."},"template":{"type":"string","description":"message/inmail/whatsapp_message body."},"text_template":{"type":"string","description":"comment_post text, or fallback for ai_prompt."},"ai_prompt":{"type":"string","description":"Paid, KG-grounded comment goal; falls back to text_template."},"subject_template":{"type":"string","description":"Required for inmail and the first email. On later email_send steps, a subject starts a new thread; omission continues the previous one."},"body_template":{"type":"string","description":"email_send body."},"sender_profile_id":{"type":"string","description":"Sender UUID. Email: this person’s inboxes, pinned per lead; a From change needs a subject. LinkedIn invite/message/inmail/withdraw share one profile or none; visit/follow/like/comment may override."},"sender_mailbox_id":{"type":"string","description":"email_send only: exact inbox UUID of a selected sender, for this step alone; not with sender_profile_id. It and the next email each need a subject."},"body_html_template":{"type":"string","description":"email_send: optional HTML part (multipart/alternative)."},"cc":{"type":"array","items":{"type":"string"},"description":"email_send: static CC addresses."},"bcc":{"type":"array","items":{"type":"string"},"description":"email_send: static BCC addresses."},"variants":{"type":"array","maxItems":25,"items":{"type":"object","additionalProperties":true},"description":"A/B copies b–z over base a: message/WhatsApp template, InMail subject/template, email subject/body/HTML. Subject-less email varies body only. Variants have stats; spintax does not."},"auto_optimize":{"type":"object","properties":{"metric":{"type":"string","enum":["reply","click","open"]},"min_sends_per_variant":{"type":"integer","minimum":1,"maximum":100000},"min_conversions":{"type":"integer","minimum":1,"maximum":100000}},"required":["metric"],"description":"Optional: every A/B step is already judged on replies (100 sends/5 replies per variant); set this for click/open or other thresholds."},"attachments":{"type":"array","maxItems":5,"items":{"type":"object","properties":{"url":{"type":"string"},"name":{"type":"string"}},"required":["url"]},"description":"LinkedIn message files fetched at dispatch time."},"send_window":{"type":"object","additionalProperties":true,"description":"email_send window; overrides the sequence's."},"days":{"type":"integer","description":"wait: delay days."},"hours":{"type":"integer","description":"wait: delay hours."},"jitter_hours":{"type":"integer","description":"wait: deterministic 0..N-hour spread across enrollments."},"reaction":{"type":"string","enum":["like","celebrate","support","funny","love","insightful"],"description":"like_post: LinkedIn reaction type."},"post_recency_days":{"type":"integer","description":"like_post/comment_post: max post age."},"on_no_post":{"type":"string","enum":["stop"],"description":"like_post/comment_post: stop when no eligible post."},"timeout_days":{"type":"integer","description":"Days before on_timeout (default 14)."},"withdraw_on_timeout":{"type":"boolean","description":"Draft-only wait_for_connection: withdraw unanswered invite before on_timeout stop/continue."},"working_days":{"type":"boolean","description":"wait: count schedule weekdays in local time (Mon–Fri UTC fallback); editable after start."},"on_timeout":{"type":"string","enum":["stop","continue"],"description":"Action at timeout_days."},"subsequence_id":{"type":"string","description":"email_enroll: optional Instantly subsequence; email_move: required target subsequence."},"signal":{"type":"string","enum":["linkedin_connected","linkedin_replied","whatsapp_replied","email_sent","email_opened","email_clicked","email_replied","email_bounced","meeting_booked","email_unsubscribed","call_connected","call_no_answer","call_voicemail","company_hiring","company_raised_funds","job_change","new_hire","web_visit","intent"],"description":"wait_for_signal gate, including engagement and external GTM signals."},"condition":{"oneOf":[{"type":"string","enum":["connection_accepted","already_connected","open_profile"]},{"type":"object","additionalProperties":true}],"description":"Connection string or {signal}/{has_contact:email|linkedin|phone}/{has_column:key}; present:false negates; all/any/not combine; then/else route. Reply-stop ends repliers before *_replied can branch; keep journeys linear."},"then":{"type":"string","description":"branch: step id if true; omit falls through."},"else":{"type":"string","description":"branch: step id if false/timeout; omit falls through."}},"required":["kind"],"additionalProperties":true}}},"required":["steps"]},"email":{"type":"object","description":"Instantly BYOK binding for delegated email_enroll/move/stop; native email needs none.","properties":{"provider":{"type":"string","enum":["instantly"]},"connection_id":{"type":"string","description":"Instantly connection id; default: the org's active one."},"definition":{"type":"object","description":"Email content spec ({ steps: [...] }) compiled into the Instantly campaign on start.","additionalProperties":true}},"additionalProperties":true},"enroll_from_table":{"type":"boolean","description":"Enroll source Table rows now: free, no sends; see enrollment."},"include_unsubscribe":{"type":"boolean","description":"First-touch email: opt-out plus one-click headers; HTML links the label, plain text adds reply_to_stop_text or a default line. Follow-ups: neither. Zapbox: link only."},"linkedin_url_column_key":{"type":"string","description":"row_values key with each lead's LinkedIn URL (else linkedin_url/linkedinUrl/linkedin/profile_url)."},"max_credits":{"type":"number"},"max_live_sends":{"type":"integer","description":"Live action ceiling; required for live email/WhatsApp/crm_task even at 0 credits."},"name":{"type":"string"},"reply_to_stop_text":{"type":"string","maxLength":500,"description":"Optional footer on first-touch emails, e.g. Reply STOP to opt out. Empty clears."},"senders":{"type":"array","items":{"type":"string"},"description":"LinkedIn/WhatsApp account ids; required before Start."},"sending_schedule":{"type":"object","description":"Default email/LinkedIn/WhatsApp window: IANA zone, ISO days 1=Mon, HH:MM start/end. LinkedIn action schedules override; account hours narrow.","properties":{"timezone":{"type":"string"},"days":{"type":"array","items":{"type":"integer"}},"start":{"type":"string"},"end":{"type":"string"}},"required":["timezone","days","start","end"]},"settings":{},"slug":{"type":"string","description":"Unique slug."},"source_table_id":{"type":"string"},"tags":{"type":"array","items":{"type":"string"},"description":"Workspace tags shared with Tables, Workflows and Knowledge."},"tracking_clicks":{},"tracking_opens":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_create"]}},"/api/cli/sequences/{sequenceId}":{"get":{"operationId":"getSequencesSequenceId","tags":["Sequences"],"summary":"Get Sequence","description":"Gets a sequence's definition, senders, status and credit usage, led by warnings and sending_schedule (each channel's window, labelled). include_readiness=true adds the launch check. include=guided_proposal reads your retained unapplied chat proposal; it neither applies changes nor starts the campaign.\n\nMCP: `oxygen_newsletters`, `oxygen_sequences_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["readiness","guided_proposal","readiness,guided_proposal","guided_proposal,readiness"],"description":"Optional readiness, guided_proposal, or both comma-separated. Proposal read is actor/activation-bound; Workspace chat metadata is shared. Read only."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_newsletters","oxygen_sequences_get"]},"patch":{"operationId":"patchSequencesSequenceId","tags":["Sequences"],"summary":"Update Sequence","description":"Updates one Sequence for 0 credits without sending; pass only changed fields. Journey/channels/email binding: draft only; sender pools require draft/paused, and launch ceilings change through oxygen_sequences_start. Name, throttles, tracking, tags, footer, and schedules stay editable. linkedin_invite_schedule and linkedin_message_schedule replace the general window for LinkedIn invites and messages/InMail; null restores inheritance. Setting fields map to settings.<same field name>, except linkedin_schedule (settings.schedule) and sending_schedule / include_unsubscribe, which each set both channel keys like the web Sending settings step and cannot be combined in one call with the per-channel fields they write. A step's own send_window still overrides email hours, and an email window in recipient-timezone mode keeps that mode (the same hours in each lead's own timezone). LinkedIn also sends only inside each LinkedIn account's working hours (default 07:00-22:00 in the account's timezone; set with oxygen_senders_limits_set); WhatsApp accounts and email mailboxes have no hours of their own. reply_to_stop_text adds an optional first-touch email footer; empty clears it.\n\nMCP: `oxygen_newsletters`, `oxygen_sequences_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"activation_id":{"type":"string","minLength":36,"maxLength":36,"description":"Guided activation UUID; requires activation_revision and expected_revision."},"activation_revision":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Current activation revision; requires activation_id and expected_revision."},"channels":{"type":"array","items":{"type":"string","enum":["linkedin","email","whatsapp","call","crm"]},"description":"Draft only: the channels this sequence uses. Omit to derive from the journey's steps."},"definition":{"type":"object","description":"{ steps: [...] } replacing the journey WHOLESALE (not a merge), same step schema as oxygen_sequences_create. After start (paused included), only wait days/hours/jitter_hours/working_days and step wording (templates, subjects, notes, variant copy) may change; keep step IDs/kinds/order and variant count. Queued unsent messages take the new wording. Connection-wait timeout_days/on_timeout/withdraw_on_timeout stay draft-only. Zero a wait instead of deleting it; oxygen_sequences_duplicate makes a draft.","properties":{"steps":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Complete replacement steps; use oxygen_sequences_create's typed definition.steps item schema. Copy may use {{sender_first_name}}, {{sender_last_name}} and {{sender_full_name}} (email adds {{sender_email}}) for the person sending each step, with no table column."}},"required":["steps"]},"email":{"type":"object","description":"Instantly BYOK binding for delegated email_enroll/move/stop; native email needs none.","properties":{"provider":{"type":"string","enum":["instantly"]},"connection_id":{"type":"string","description":"Instantly connection id; default: the org's active one."},"definition":{"type":"object","description":"Email content spec ({ steps: [...] }) compiled into the Instantly campaign on start.","additionalProperties":true}},"additionalProperties":true},"expected_revision":{"type":"string","pattern":"^[a-f0-9]{64}$","description":"Exact sequence_revision from get; stale edits refuse, not launch approval."},"include_unsubscribe":{"type":"boolean","description":"First-touch email: opt-out plus one-click headers; HTML links the label, plain text adds reply_to_stop_text or a default line. Follow-ups: neither. Zapbox: link only."},"linkedin_url_column_key":{"type":"string","description":"row_values key holding each lead's LinkedIn profile URL (else falls back to linkedin_url/linkedinUrl/linkedin/profile_url). Editable on a non-archived sequence; \"\" clears it back to auto-detect."},"max_credits":{"type":"number","description":"Credit cap for the LinkedIn track (draft only)."},"max_live_sends":{"type":"integer","description":"Hard ceiling on total LIVE external actions (draft only; locked after start). REQUIRED for email, WhatsApp, or crm_task live execution."},"name":{"type":"string"},"reply_to_stop_text":{"type":"string","maxLength":500,"description":"Optional footer on first-touch emails, e.g. Reply STOP to opt out. Empty clears."},"senders":{"type":"array","items":{"type":"string"},"description":"LinkedIn/WhatsApp account ids (or connection / Unipile ids) attached directly, besides sender_profile_ids' own accounts; replaces that set, [] removes them. oxygen_sequences_get lists both under sender_pool. Draft/paused only."},"sending_schedule":{"type":"object","description":"Default email/LinkedIn/WhatsApp window: IANA zone, ISO days 1=Mon, HH:MM start/end. LinkedIn action schedules override; account hours narrow.","properties":{"timezone":{"type":"string"},"days":{"type":"array","items":{"type":"integer"}},"start":{"type":"string"},"end":{"type":"string"}},"required":["timezone","days","start","end"]},"settings":{},"source_table_id":{"type":"string","description":"Bind the table this sequence enrolls leads from (id or slug). Draft/paused may rebind. Existing enrollments retain their source-row provenance."},"tags":{"type":"array","items":{"type":"string"},"description":"Replace the sequence's workspace tags (whole-set; [] clears). Works on archived sequences too."},"tracking_clicks":{"type":"boolean","description":"Per-sequence CLICK tracking toggle for native email sends (default false; editable any time, even after start). false leaves the email's links untouched instead of rewriting them into click-tracked redirects. Same verified-tracking-domain + secret gates as tracking_opens."},"tracking_opens":{"type":"boolean","description":"Per-sequence OPEN tracking toggle for native email sends (default false; editable any time, even after start). false skips the 1x1 open-pixel injection for this sequence — a deliverability knob (a pixel is spam-filter surface). Injection additionally requires a verified tracking domain (oxygen_domains_tracking_status) and the deployment tracking secret."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_newsletters","oxygen_sequences_update"]},"delete":{"operationId":"deleteSequencesSequenceId","tags":["Sequences"],"summary":"Delete Sequence","description":"PERMANENTLY deletes a sequence and everything it owns — enrollments, actions, sender links, schedules. An active sequence must be paused first. Two-step gate: the first call returns a preview of the blast radius (enrollments + live sends already made) and deletes nothing; repeat with approved=true to purge. To stop dispatch temporarily without deleting the sequence, use oxygen_sequences_set_status with status 'paused'.\n\nMCP: `oxygen_sequences_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"approved","in":"query","required":false,"schema":{"type":"boolean","description":"Confirm the previewed permanent deletion. Omit to preview first."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_sequences_delete"]}},"/api/cli/sequences/{sequenceId}/contacts":{"get":{"operationId":"getSequencesSequenceIdContacts","tags":["Sequences"],"summary":"List Sequence Contacts","description":"Lists campaign contacts with every source variable, contact tags, and the factual or assigned sender. A contact carries every tag it reached: contacted means an invite, message or email was sent (a profile visit is not), and a positive reply is also replied and contacted. Removed contacts stay hidden; source rows are kept. Paged via next_cursor/offset.\n\nMCP: `oxygen_sequences_contacts`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"contact_state","in":"query","required":false,"schema":{"type":"string","description":"Contacts with any of these tags, comma-separated: not_contacted, contacted, connected, replied, positive_reply. Default all."}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"next_cursor of the prior page."}},{"name":"exclude_contact_state","in":"query","required":false,"schema":{"type":"string","description":"Hide contacts with any of these tags, comma-separated."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"description":"Per page, 1–500; default 25."}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Rows to skip; alternative to cursor."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_contacts"]},"post":{"operationId":"postSequencesSequenceIdContacts","tags":["Sequences"],"summary":"Remove Sequence Contacts","description":"Previews or applies permanent campaign-only removal of table_row_ids or of leads whose source row was deleted (missing_source_rows=true; preview names them). Stops queued work, keeps rows and history.\n\nMCP: `oxygen_sequences_contacts_remove`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Apply; false or omitted previews."},"missing_source_rows":{"type":"boolean","description":"Instead of ids: enrolled leads whose source row was deleted (500 per call)."},"table_row_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500,"description":"Selected source-row UUIDs; in a sequence still in dry run, also a finished dry-run lead a live start would restart."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_sequences_contacts_remove"]}},"/api/cli/sequences/{sequenceId}/contacts/rows":{"get":{"operationId":"sequences.contacts.rows","tags":["Sequences"],"summary":"Sequences contacts rows","description":"Read the full contact grid projection with exact contact-state filter and native synthetic status columns.\n\nCLI: `oxygen sequences contacts rows`.\n\nMCP: `oxygen_sequence_contacts_rows`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"contact_state","in":"query","required":false,"schema":{"type":"string","enum":["all","not_contacted","contacted","connected","replied","positive_reply"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":2000}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"f","in":"query","required":false,"schema":{"type":"string","description":"Filter tree as the grid URL's f parameter (base64url JSON); copy it from a filtered browser view."}},{"name":"s","in":"query","required":false,"schema":{"type":"string","description":"Sort list as the grid URL's s parameter (base64url JSON); copy it from a sorted browser view."}},{"name":"fields","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated column keys to return, e.g. full_name,company,__seq_status; omit for every column."}},{"name":"projection","in":"query","required":false,"schema":{"type":"string","enum":["grid","values"],"description":"values: compact {id, values} rows, long values capped; grid (default): the full grid payload."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequence_contacts_rows"],"x-oxygen-cli-command":"oxygen sequences contacts rows"}},"/api/cli/sequences/{sequenceId}/duplicate":{"post":{"operationId":"postSequencesSequenceIdDuplicate","tags":["Sequences"],"summary":"Duplicate Sequence","description":"Copies a sequence as a new draft: steps, channels, settings, source table, caps, tags and (unless include_senders=false) senders. Never enrollments, stats, A/B decisions or a linked Instantly campaign; not_copied lists what was left. The way to change a started journey's steps. 0 credits; nothing sends until oxygen_sequences_start.\n\nMCP: `oxygen_sequences_duplicate`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"include_senders":{"type":"boolean","description":"Copy the sender pool (default true)."},"name":{"type":"string","description":"Default '<source name> (copy)'."},"slug":{"type":"string","description":"Default '<source slug>-copy' (then -copy-2…)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_duplicate"]}},"/api/cli/sequences/{sequenceId}/enroll":{"post":{"operationId":"postSequencesSequenceIdEnroll","tags":["Sequences"],"summary":"Enroll Leads into Sequence","description":"Enrolls leads into a sequence (0 credits; an active sequence contacts them on its next tick, draft/paused hold them till started). from_table:true: unenrolled bound rows, max 500/call; repeat while from_table.has_more. LinkedIn: lead_provider_id (ACo…), lead_profile_url or row's linkedin_url_column_key; /in/ URLs or hyphen/digit handles resolve at send. Inferred handles: linkedin_handles_canonicalized; single words refused. Not enrolled: unresolved_linkedin_leads/unresolved_linkedin_lead_details (cap50,*_truncated). No profile: other channels can enroll (linkedin_unavailable_lead_details). Email/WhatsApp row_values.email/phone and lead_profile_url leads auto-file/dedupe in leads table; creates/binds if absent (leads_table/web_url). CRM tasks, alone/mixed: stable table_row_id/lead_provider_id + mapped row_values without email/LinkedIn/phone; mappings validate at planning. Missing-channel steps skip. Association id names destination. table_row_id snapshots cells incl. AI/tool outputs to row_values; explicit win. Idempotent by table_row_id/email/phone. WhatsApp-only dedupes normalized phone across rows/statuses; mixed journeys skip duplicate WhatsApp steps. LinkedIn/company DNC always; exclude_contacted/suppress_list: skipped_by_reason.\n\nMCP: `oxygen_sequences_enroll`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"exclude_contacted":{"type":"boolean","description":"Skip leads whose LinkedIn identity is still enrolled in another active sequence. Omitted: sequence default (off unless set)."},"from_list":{"type":"string","description":"Sending-domain Sequence's own subscription list id/key; 500 addresses/call."},"from_list_after":{"type":"string","description":"Prior from_list.next_after."},"from_table":{"type":"boolean","description":"Unenrolled bound source-table rows, max 500/call; repeat while response.from_table.has_more. Not with leads."},"ignore_sender_bindings":{"type":"boolean","description":"Override one-person-one-sender: enroll leads owned outside this sender pool; else skipped_by_reason.bound_to_other_sender. Default off."},"leads":{"type":"array","description":"Leads to enroll.","items":{"type":"object","properties":{"table_row_id":{"type":"string"},"lead_provider_id":{"type":"string"},"lead_profile_url":{"type":"string"},"lead_name":{"type":"string"},"row_values":{"type":"object","additionalProperties":true}},"required":[],"additionalProperties":false}},"suppress_list":{"type":"array","items":{"type":"string"},"description":"Provider ids excluded for this call: skipped_by_reason.on_request_suppress_list."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_enroll"]}},"/api/cli/sequences/{sequenceId}/enrollments":{"get":{"operationId":"getSequencesSequenceIdEnrollments","tags":["Sequences"],"summary":"List Sequence Enrollments","description":"Lists per-lead enrollment state with current step and the latest action's status, error, attempt/max-attempt count, ready/retry time, and dispatch time. view=compact gives one short row per lead (invite state, accepted_at, next_due). next_due.summary says when the next message is due in words, at_local in the campaign timezone; reasons: step_scheduled (planned send; held_by names a hold, e.g. send_cap_reached), planner_due, not_started (begins on start/resume), nothing_scheduled (no step will run), finished; waiting_for_connection/waiting_for_signal have no send time, gives_up_at ends the wait (on_timeout: stop leaves, continue moves on), and acceptance makes the next step due at once. A failed lead carries failure: cause in words (cause_recorded=false when it was never recorded) and provider_contact (made, none = never started, nothing_sent, unknown). missing_source_row=true: the lead's source-table row was deleted but it is still enrolled (oxygen_sequences_contacts_remove with missing_source_rows=true removes it); null: no live source table to check. Use to inspect why leads are stuck before deciding whether recovery is needed. channels: usable = the sequence's channels that reach this lead; unavailable [{channel, reason}]: no_linkedin_profile (LinkedIn steps skipped; other channels may continue), linkedin_profile_unreadable (LinkedIn would not open the profile; same), no_recipient_email, no_phone_number.\n\nMCP: `oxygen_sequences_enrollments`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"invite","in":"query","required":false,"schema":{"type":"string","enum":["accepted","pending","not_invited"],"description":"Optional: LinkedIn invite state. accepted = invited and connected; pending = not accepted yet; not_invited = no invite."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Optional: max enrollments to return."}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Optional: next_offset from the previous page."}},{"name":"order","in":"query","required":false,"schema":{"type":"string","enum":["created","due"],"description":"Optional: due = soonest next_due.at first, then waiting leads by gives_up_at."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Optional: filter by enrollment status (e.g. pending, active, waiting_connection, failed). pending = not started; waiting_connection = invite not accepted. Status is progress, not the invite: use invite=accepted for accepted leads."}},{"name":"step","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Optional: only leads on this 0-based step."}},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["full","compact"],"description":"Optional: compact = one short row per lead."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_enrollments"]}},"/api/cli/sequences/{sequenceId}/esp":{"get":{"operationId":"getSequencesSequenceIdEsp","tags":["Sequences"],"summary":"ESP Matching","description":"ESP breakdown of a sequence's email scope: the provider each enrolled lead's mail routes through (google/microsoft, named gateways like Proofpoint resolved behind via SPF, and non-matchable hosts), folded against the sending mailbox pool, plus how many leads the current esp_matching mode would defer. Preview before enabling 'strict'/'prefer'. Resolves via MX+SPF (0 credits) and caches the result. Read-only.\n\nMCP: `oxygen_sequences_esp`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"max_lookups","in":"query","required":false,"schema":{"type":"number","description":"Cap uncached domains resolved over DNS this call (0-2000); the rest are reported as domains_unresolved. Omit for the default cap."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_esp"]}},"/api/cli/sequences/{sequenceId}/events":{"get":{"operationId":"getSequencesSequenceIdEvents","tags":["Sequences"],"summary":"Sequence Activity","description":"Per-sequence activity feed: sends, failures, skips, opens/clicks (bot-filtered unless include_bots), replies, bounces, unsubscribes, and positive reply-status — newest first. Email events preserve mailbox_id, mailbox_email, and sending_domain when provenance can resolve them. Keyset-paginated via before/next_before; filter by enrollment and/or kinds. Read-only, no credits.\n\nMCP: `oxygen_sequences_events`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"before","in":"query","required":false,"schema":{"type":"string","description":"Keyset cursor: events before this ISO time; pass the prior next_before."}},{"name":"enrollment","in":"query","required":false,"schema":{"type":"string","description":"Scope to one enrollment id."}},{"name":"include_bots","in":"query","required":false,"schema":{"type":"boolean","description":"Include bot opens/clicks (off by default)."}},{"name":"kinds","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Kinds: sent/failed/skipped/open/click/replied/bounced/unsubscribed/positive; omit for all."}},{"name":"limit","in":"query","required":false,"schema":{"type":"number","description":"Max events (1-200, default 50)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_events"]}},"/api/cli/sequences/{sequenceId}/leads/rows":{"get":{"operationId":"sequences.leads.rows","tags":["Sequences"],"summary":"Sequences leads rows","description":"Read the complete enrolled-lead grid projection, including sequence status, step, action and failure columns.\n\nCLI: `oxygen sequences leads rows`.\n\nMCP: `oxygen_sequence_leads_rows`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":2000}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"f","in":"query","required":false,"schema":{"type":"string","description":"Filter tree as the grid URL's f parameter (base64url JSON); copy it from a filtered browser view."}},{"name":"s","in":"query","required":false,"schema":{"type":"string","description":"Sort list as the grid URL's s parameter (base64url JSON); copy it from a sorted browser view."}},{"name":"fields","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated column keys to return, e.g. full_name,company,__seq_status; omit for every column."}},{"name":"projection","in":"query","required":false,"schema":{"type":"string","enum":["grid","values"],"description":"values: compact {id, values} rows, long values capped; grid (default): the full grid payload."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequence_leads_rows"],"x-oxygen-cli-command":"oxygen sequences leads rows"}},"/api/cli/sequences/{sequenceId}/recipients":{"get":{"operationId":"getSequencesSequenceIdRecipients","tags":["Sequences"],"summary":"GET /api/cli/sequences/{sequenceId}/recipients","description":"Fields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{}},{"name":"offset","in":"query","required":false,"schema":{}},{"name":"status","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false}},"/api/cli/sequences/{sequenceId}/reconcile":{"post":{"operationId":"postSequencesSequenceIdReconcile","tags":["Sequences"],"summary":"Reconcile Ambiguous LinkedIn Send","description":"Checks whether one failed/canceled live LinkedIn invite, message, or InMail actually landed at the provider. Requires a paused sequence; provider reads only. Preview by default; approved=true backfills an exact match into local action/enrollment state — never resends or writes to the provider. Zero credits.\n\nMCP: `oxygen_sequences_reconcile`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action_id":{"type":"string","description":"Failed/canceled live action UUID."},"approved":{"type":"boolean","description":"True applies an exact match to local state; never sends."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_reconcile"]}},"/api/cli/sequences/{sequenceId}/recover-capacity":{"post":{"operationId":"postSequencesSequenceIdRecoverCapacity","tags":["Sequences"],"summary":"Recover Definitive No-Effect Failures","description":"Read-only by default: previews the exact terminal Sequence actions Oxygen can prove were not applied and knows how to replay safely—provider-capacity denials plus explicitly allowlisted Oxygen request-format defects. The result includes row fingerprints, exclusions, a zero-cost safety envelope, and a short-lived signed approval token. approved=true requires that exact approval_token and a paused Sequence, then atomically restores only the bound local action/enrollment state while keeping dispatch paused. It never calls a provider, writes externally, or spends credits; ordinary recipient failures and ambiguous effects are excluded.\n\nMCP: `oxygen_sequences_recover_capacity`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approval_token":{"type":"string","description":"Exact unexpired token returned by a prior preview. Valid only with approved=true."},"approved":{"type":"boolean","description":"True applies the exact signed scope. Requires approval_token; the Sequence remains paused."},"limit":{"type":"integer","minimum":1,"maximum":5000,"description":"Maximum candidate failure rows to inspect (default 500). A truncated preview cannot be approved."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_recover_capacity"]}},"/api/cli/sequences/{sequenceId}/render":{"get":{"operationId":"getSequencesSequenceIdRender","tags":["Sequences"],"summary":"Render Sequence Copy","description":"Renders a sequence's copy like the web step editor's Preview: every A/B variant of each step (email subject/body, LinkedIn note/message/InMail, WhatsApp, comments) for leads of the bound table (sample values without one), signed by one eligible sender. Works on a draft with nobody enrolled; email copy is rendered here, not in the start preview. Each field lists missing_variables. Read-only, 0 credits.\n\nMCP: `oxygen_sequences_render`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"sender","in":"query","required":false,"schema":{}},{"name":"step","in":"query","required":false,"schema":{}},{"name":"variant","in":"query","required":false,"schema":{"type":"string","description":"Only this variant ('a' is the base step, then b, c…)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_render"]}},"/api/cli/sequences/{sequenceId}/retry-deferred":{"post":{"operationId":"postSequencesSequenceIdRetryDeferred","tags":["Sequences"],"summary":"Retry Deferred Sequence Actions","description":"Preview or re-ready pending actions deferred by LinkedIn working hours or an email send window. The sequence must be paused. Email actions refresh their snapshotted window from the current campaign settings. Preview by default; approved=true resets only the bounded listed actions to now while keeping the sequence paused. This performs no provider call, spends zero credits, and never bypasses window, sender-spacing, quota, or campaign-cap checks when resumed.\n\nMCP: `oxygen_sequences_retry_deferred`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"True applies the bounded local retry; the sequence remains paused."},"limit":{"type":"integer","minimum":1,"maximum":500,"description":"Maximum actions to preview/retry (default 100)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_retry_deferred"]}},"/api/cli/sequences/{sequenceId}/signal":{"post":{"operationId":"postSequencesSequenceIdSignal","tags":["Sequences"],"summary":"Record Sequence Signal","description":"Records an external GTM signal onto a running sequence's enrollment(s) to drive signal-triggered branch/wait_for_signal control. Target an enrollment by enrollment_id and/or lead_provider_id (at least one required) — lead_provider_id matches every enrollment of that lead in the sequence. This is a CONTROL action: it only records that the signal occurred (advancing waits and routing branches on the next dispatch tick); it never sends anything and consumes 0 credits.\n\nMCP: `oxygen_sequences_signal`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"enrollment_id":{"type":"string","description":"Target a specific enrollment by id. At least one of enrollment_id or lead_provider_id is required."},"lead_provider_id":{"type":"string","description":"Target every enrollment of this lead (LinkedIn ACo... id) in the sequence. At least one of enrollment_id or lead_provider_id is required."},"signal":{"type":"string","enum":["linkedin_connected","linkedin_replied","whatsapp_replied","email_sent","email_opened","email_clicked","email_replied","email_bounced","meeting_booked","email_unsubscribed","call_connected","call_no_answer","call_voicemail","company_hiring","company_raised_funds","job_change","new_hire","web_visit","intent"],"description":"The external GTM signal to record on the enrollment(s)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_signal"]}},"/api/cli/sequences/{sequenceId}/standby":{"get":{"operationId":"sequences.standby.get","tags":["Sequences"],"summary":"Sequences standby get","description":"Read automatic mailbox replacement policy, ready reserve and replacements for a campaign.\n\nCLI: `oxygen sequences standby get`.\n\nMCP: `oxygen_sequences_standby_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_standby_get"],"x-oxygen-cli-command":"oxygen sequences standby get"},"patch":{"operationId":"sequences.standby.set","tags":["Sequences"],"summary":"Sequences standby set","description":"Enable or disable automatic replacement after bounce protection pauses a mailbox. Preview first; apply with approved and returned plan. Shared reserves may change sender identity for uncontacted leads. Contacted leads keep their original inbox and hold follow-ups. 0 credits.\n\nCLI: `oxygen sequences standby set`.\n\nMCP: `oxygen_sequences_standby_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"approved":{"type":"boolean"},"plan":{"type":"string"}},"required":["enabled"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_standby_set"],"x-oxygen-cli-command":"oxygen sequences standby set"}},"/api/cli/sequences/{sequenceId}/standing-approval":{"get":{"operationId":"getSequencesSequenceIdStandingApproval","tags":["Sequences"],"summary":"GET /api/cli/sequences/{sequenceId}/standing-approval","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false},"post":{"operationId":"postSequencesSequenceIdStandingApproval","tags":["Sequences"],"summary":"POST /api/cli/sequences/{sequenceId}/standing-approval","description":"Fields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{},"draft_samples":{},"max_credits":{},"preview_hash":{},"sample_size":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true}},"/api/cli/sequences/{sequenceId}/start":{"post":{"operationId":"postSequencesSequenceIdStart","tags":["Sequences"],"summary":"Start Sequence","description":"Preview free with approved=false via oxygen_capabilities_read. max_credits 0 spends nothing; AI comments refuse it. Guided LinkedIn needs a positive action cap and echoes preview.launch_review to start. Review senders, recipients, copy, schedule, blockers. Start enrolls unenrolled table rows first. Live start sends outreach/CRM writes. Changed inputs need a new preview.\n\nMCP: `oxygen_sequences_start`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"true starts live; false/omitted previews."},"dry_run":{"type":"boolean","description":"Simulate with no effects/credits; live restart rechecks exclusions."},"launch_review":{"type":"object","additionalProperties":false,"properties":{"digest":{"type":"string","pattern":"^[a-f0-9]{64}$"},"expires_at":{"type":"string","minLength":1},"max_live_sends":{"type":"integer","minimum":1},"max_credits":{"type":"number","minimum":0}},"required":["digest","expires_at","max_live_sends","max_credits"]},"max_credits":{"type":"number","minimum":0},"max_live_sends":{"type":"integer","minimum":1,"description":"External-action cap; required for email/WhatsApp/CRM tasks. Newsletter: max_sends."},"start_at":{"type":"string","description":"Draft only; ISO+zone, ≤30d ahead."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_start"]}},"/api/cli/sequences/{sequenceId}/stats":{"get":{"operationId":"getSequencesSequenceIdStats","tags":["Sequences"],"summary":"Sequence Funnel","description":"Shows one Sequence's persisted launch status separately from its current shared operational state, reason codes, open work, lifetime sent/terminal-failed/deferral analytics by action kind and failure class, exact link, zero-cost proof, funnels (null=unmeasured), and daily-budget posture.\n\nMCP: `oxygen_sequences_stats`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}},{"name":"interval","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_stats"]}},"/api/cli/sequences/{sequenceId}/status":{"post":{"operationId":"postSequencesSequenceIdStatus","tags":["Sequences"],"summary":"Pause / Resume Sequence","description":"Transitions an active/paused sequence's operational status: 'paused' pauses dispatch (resumable), 'active' resumes a paused sequence; one paused at its live send cap re-pauses until oxygen_sequences_start raises max_live_sends. There is no archive: a sequence a workspace is done with is deleted (oxygen_sequences_delete). To start a draft sequence, use oxygen_sequences_start (approval-gated) instead.\n\nMCP: `oxygen_sequences_set_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","paused","draft"],"description":"active = resume, paused = pause, draft = cancel a scheduled start before it comes."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_sequences_set_status"]}},"/api/cli/sequences/{sequenceId}/test-send":{"get":{"operationId":"getSequencesSequenceIdTestSend","tags":["Sequences"],"summary":"Newsletters","description":"Newsletter email steps. content_get/content_set: the step's HTML (≤100 KB, revisioned; drafts only); merge tags are HTML-escaped; {{unsubscribe_url}} places the opt-out, else a footer is added. test_send: [Test] copy to ≤5 member emails (`to`; omit to list), 0.05 credits each, 20/day. templates (with starters); template_save (sequence+step_id, from_document_id, starter_id or html); template_rename/_delete (template_id). asset_upload hosts an image (source_url, or content_base64 ≤2 MB) and returns its URL; asset_list pages them. stats: deliveries, est. opens, link clicks, bounces, complaints, unsubscribes; recipients: statuses. Else 0 credits.\n\nMCP: `oxygen_newsletters`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_newsletters"]},"post":{"operationId":"postSequencesSequenceIdTestSend","tags":["Sequences"],"summary":"Newsletters","description":"Newsletter email steps. content_get/content_set: the step's HTML (≤100 KB, revisioned; drafts only); merge tags are HTML-escaped; {{unsubscribe_url}} places the opt-out, else a footer is added. test_send: [Test] copy to ≤5 member emails (`to`; omit to list), 0.05 credits each, 20/day. templates (with starters); template_save (sequence+step_id, from_document_id, starter_id or html); template_rename/_delete (template_id). asset_upload hosts an image (source_url, or content_base64 ≤2 MB) and returns its URL; asset_list pages them. stats: deliveries, est. opens, link clicks, bounces, complaints, unsubscribes; recipients: statuses. Else 0 credits.\n\nMCP: `oxygen_newsletters`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"sample_lead":{"type":"object","description":"test_send: merge values."},"step_id":{"type":"string","description":"The email_send step."},"to":{"type":"array","items":{"type":"string"},"maxItems":5,"description":"Member emails."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_newsletters"]}},"/api/cli/sequences/{sequenceId}/unschedule":{"post":{"operationId":"postSequencesSequenceIdUnschedule","tags":["Sequences"],"summary":"Pause / Resume Sequence","description":"Transitions an active/paused sequence's operational status: 'paused' pauses dispatch (resumable), 'active' resumes a paused sequence; one paused at its live send cap re-pauses until oxygen_sequences_start raises max_live_sends. There is no archive: a sequence a workspace is done with is deleted (oxygen_sequences_delete). To start a draft sequence, use oxygen_sequences_start (approval-gated) instead.\n\nMCP: `oxygen_sequences_set_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_sequences_set_status"]}},"/api/cli/sequences/{sequenceId}/variants":{"get":{"operationId":"getSequencesSequenceIdVariants","tags":["Sequences"],"summary":"Sequence A/B Scoreboard","description":"Shows a sequence's generic per-step action/base-variant scoreboard plus fact-grade email attribution by sending mailbox and sending domain: sent, replies, positive replies, reply-type counts, bounces, failures, reply rate, and bounce rate. This is not the copy-only analytics.messagePerformance view: base rows can represent non-message actions, and campaign replies may lack step/variant provenance. Reply/bounce facts prefer the exact inbox/conversation mailbox; any campaign facts without a preserved sending identity remain explicit under unattributed instead of being guessed. Also returns the reversible auto-winner state (by_state). Rates are raw, not the funnels tri-state (oxygen_sequences_stats). To act on variants, use oxygen_sequences_variants_action.\n\nMCP: `oxygen_sequences_variants`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_variants"]},"post":{"operationId":"postSequencesSequenceIdVariants","tags":["Sequences"],"summary":"Act on the A/B Scoreboard","description":"Mutates a sequence's A/B auto-winner state — the reversible control behind oxygen_sequences_variants. action='auto_optimize' runs the auto-winner now on every step with variants (pauses variants converting below the leader once each clears the step's thresholds, default 100 sends/5 replies; metric reply unless the step's auto_optimize names click/open, which need native tracking; nothing runs while the sequence's auto_optimize is false). action='pause'/'activate' manually overrides one (step_id, variant) status. action='reset' clears auto/manual decisions for a variant, a step, or the whole sequence (reactivating the affected variants). All actions are internal state changes — free, reversible, and no external send happens from this call. Returns the applied action, the resulting state, a note, and a web_url deep-link.\n\nMCP: `oxygen_sequences_variants_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"sequenceId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["auto_optimize","pause","activate","reset"],"description":"auto_optimize = run the auto-winner now (whole sequence; no step_id/variant); pause/activate = manual override of one (step_id, variant); reset = clear decisions (optionally scoped by step_id and/or variant)."},"step_id":{"type":"string","description":"Step id. Required for pause/activate; optional scope for reset."},"variant":{"type":"string","description":"Variant id ('a' is the base step). Required for pause/activate; optional scope for reset."},"variant_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_variants_action"]}},"/api/cli/sequences/analytics":{"get":{"operationId":"getSequencesAnalytics","tags":["Sequences"],"summary":"Sequencer Analytics","description":"Shows selected-window Sequence health: persisted/operational state, fleet markedActive versus operationallyLive, open work, outcomes by action kind/failure class, exact links and per-campaign funnels (null=unmeasured). Org roster is latest 500, not proven global coverage. With sequence scope, senderPerformance and messagePerformance report senders and copy-bearing variants (absent for note-less connect-only campaigns); older unattributed replies stay in campaign totals without being guessed into a message row. Optional summary describes scope/indices; value+path retrieves complete charts or copy in signed lossless windows with unchanged selection. Legacy output/widget stays full.\n\nMCP: `oxygen_sequences_analytics`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_analytics"]}},"/api/cli/sequences/company-pauses":{"get":{"operationId":"getSequencesCompanyPauses","tags":["Sequences"],"summary":"List Paused Companies","description":"Lists companies paused in your campaigns (by a reply awaiting or after classification, or by hand/automation) with the leads each holds.\n\nMCP: `oxygen_sequences_company_pauses`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"include_released","in":"query","required":false,"schema":{"type":"boolean","description":"Include resumed pauses."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"description":"Default 100."}},{"name":"sequence_id","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sequences_company_pauses"]},"post":{"operationId":"postSequencesCompanyPauses","tags":["Sequences"],"summary":"Pause Company","description":"Pauses messaging to one company in your campaigns (all, or only sequence_ids) until resumed, e.g. after a meeting is booked. The action for automations like 'meeting booked in the CRM → stop outreach to that company'. Holds its leads by work-email domain, company domain, or LinkedIn company page; nothing is sent to them. From a crm.activity_created workflow trigger pass record_id = trigger.input.links[0].row_id. dry_run previews the leads held.\n\nMCP: `oxygen_sequences_company_pause`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Company domain, e.g. acme.com."},"dry_run":{"type":"boolean","description":"Preview; change nothing."},"email":{"type":"string","description":"A work email at the company; personal mail hosts are refused."},"linkedin_company_url":{"type":"string","description":"LinkedIn company page URL."},"note":{"type":"string","description":"Why it is paused (max 500 chars)."},"record_id":{"type":"string","description":"CRM company, person or deal record id."},"sequence_ids":{"type":"array","items":{"type":"string"},"description":"Campaign ids or slugs; omit for every campaign."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_company_pause"]}},"/api/cli/sequences/company-pauses/resume":{"post":{"operationId":"postSequencesCompanyPausesResume","tags":["Sequences"],"summary":"Resume Company","description":"Resumes messaging to a paused company: its held leads continue where they stopped (due steps spread over the next hour). Name one pause by hold_id, or the company by one identity; sequence_ids narrows it.\n\nMCP: `oxygen_sequences_company_resume`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Company domain, e.g. acme.com."},"email":{"type":"string","description":"A work email at the company; personal mail hosts are refused."},"hold_id":{"type":"string","description":"id from oxygen_sequences_company_pauses."},"linkedin_company_url":{"type":"string","description":"LinkedIn company page URL."},"record_id":{"type":"string","description":"CRM company, person or deal record id."},"sequence_ids":{"type":"array","items":{"type":"string"},"description":"Only these campaigns (ids or slugs)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_company_resume"]}},"/api/cli/sequences/draft":{"post":{"operationId":"postSequencesDraft","tags":["Sequences"],"summary":"Draft Sequence with AI","description":"Drafts an email or LinkedIn sequence with AI, grounded in confirmed workspace Knowledge with cited provenance. PAID: max_credits bounds generation. Email default; LinkedIn uses invite/message actions and waits. create=true with name+slug saves an inert draft; enrollment and launch remain separate.\n\nMCP: `oxygen_sequences_draft`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"activation_id":{"type":"string","minLength":36,"maxLength":36,"description":"Guided activation UUID; create reuses its bound native draft."},"audience":{"type":"string","description":"Who it targets; sharpens Knowledge Graph retrieval."},"channel":{"type":"string","enum":["email","linkedin"],"description":"Email default; linkedin drafts invite/message steps."},"create":{"type":"boolean","description":"Save as a DRAFT sequence (needs name + slug). Default false (preview only)."},"goal":{"type":"string","description":"Plain-language goal the copy is written to (e.g. 'book demos with RevOps leaders at Series A SaaS')."},"max_credits":{"type":"number","exclusiveMinimum":0,"description":"Credit ceiling for the AI call. Required."},"name":{"type":"string","description":"Sequence name (required when create=true)."},"slug":{"type":"string","description":"Unique slug (required when create=true)."},"source_table":{"type":"string","description":"Source table id whose column keys become the {{column|fallback}} personalization tokens."},"source_table_id":{},"steps":{"type":"integer","minimum":1,"maximum":7,"description":"Outreach actions excluding waits; default 4 email or 3 LinkedIn."},"variants":{"type":"integer","minimum":1,"maximum":3,"description":"Copy variants per email for A/B (1-3). Default 1."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_draft"]}},"/api/cli/sequences/push-external":{"post":{"operationId":"postSequencesPushExternal","tags":["Sequences"],"summary":"Push Rows into External Campaign","description":"Pushes selected Table rows into an EXISTING external sequencer campaign (Smartlead, Instantly, lemlist, HeyReach) through the workspace's own connection; dry_run previews, live requires approved. External write, 0 credits (BYOK). dry_run returns the resolved campaign, the field mapping, three sample leads exactly as they will be sent, and the row counts. Live queues a durable per-row run: each row's provider response lands in its own cell as provenance, and a row already pushed is skipped unless force. The preview's `live_executable` says whether Oxygen can queue the live push for that provider. For an Oxygen-native Sequence use oxygen_sequences_create + oxygen_sequences_enroll.\n\nMCP: `oxygen_sequences_push_external`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required for mode 'live' after inspecting the dry run."},"campaign":{"type":"string","description":"Campaign name or id as it exists in that tool. A name resolves by exact id, then exact name, then a unique partial match; more than one match is refused with candidates."},"campaign_id":{},"campaign_name":{},"connectionId":{},"connection_id":{"type":"string","description":"Specific integration connection. Defaults to the workspace's active one for that provider."},"fieldMapping":{},"field_mapping":{"type":"object","description":"Override the detected column mapping. Values are column KEYS on the table.","properties":{"email":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"company":{"type":"string"},"website":{"type":"string"},"linkedin_url":{"type":"string"},"phone":{"type":"string"},"job_title":{"type":"string"}},"additionalProperties":false},"force":{"type":"boolean","description":"Push rows that already carry a successful push to this campaign."},"from_table":{},"live":{},"mode":{"type":"string","enum":["dry_run","live"],"description":"Defaults to dry_run."},"provider":{"type":"string","enum":["smartlead","instantly","lemlist","heyreach"],"description":"The external sequencer holding the campaign."},"rowIds":{},"row_ids":{},"selection":{"type":"object","description":"{ mode: 'row_ids', row_ids: [...] } or { mode: 'all_matching', filters: [...], excluded_row_ids: [...] }. Omit for the whole table (capped at 5000 rows; has_more reports the rest).","additionalProperties":true},"senderAccountId":{},"sender_account_id":{"type":"string","description":"HeyReach only: the LinkedIn sender account the leads are added against (heyreach.linkedin_accounts_get_all lists them). Required for heyreach."},"source_table_id":{},"table":{"type":"string","description":"Table id or slug whose rows are pushed."},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_push_external"]}},"/api/cli/sequences/send":{"post":{"operationId":"postSequencesSend","tags":["Sequences"],"summary":"Send New LinkedIn Message","description":"Starts a net-new LinkedIn conversation through hosted Sequences; reply to an existing thread with oxygen_inbox_send. First call with recipient + text + sender creates a no-send/no-credit preview. After showing it, call again with the returned sequence and approved=true.\n\nMCP: `oxygen_sequences_send`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Set true only after showing the preview."},"max_credits":{"type":"number","description":"Optional credit ceiling; the message costs 0."},"recipient":{"type":"string","description":"LinkedIn /in/ profile URL or provider member id; preview only."},"recipient_name":{"type":"string","description":"Optional enrollment display name; preview only."},"sender":{"type":"string","description":"Connected LinkedIn sender reference; preview only. Discover with oxygen_senders_list."},"sequence":{"type":"string","description":"Sequence id from preview; approval pass only."},"text":{"type":"string","description":"Message body; preview only."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_sequences_send"]}},"/api/cli/sessions":{"get":{"operationId":"sessions.list","tags":["Sessions"],"summary":"Sessions list","description":"List your personal CLI sessions across workspaces, including your organizations; OAuth or personal user session required, organization API keys are refused.\n\nCLI: `oxygen sessions list`.\n\nMCP: `oxygen_sessions_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_sessions_list"],"x-oxygen-cli-command":"oxygen sessions list"}},"/api/cli/sessions/{id}":{"delete":{"operationId":"sessions.revoke","tags":["Sessions"],"summary":"Sessions revoke","description":"Revoke one personal CLI session; if this client uses it, calls stop until you reconnect with a new session. OAuth or personal user session required; organization API keys are refused.\n\nCLI: `oxygen sessions revoke`.\n\nMCP: `oxygen_sessions_revoke`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_sessions_revoke"],"x-oxygen-cli-command":"oxygen sessions revoke"}},"/api/cli/settings/beta-features":{"get":{"operationId":"settings.beta.get","tags":["Settings"],"summary":"Settings beta features get","description":"Read this workspace's beta-navigation opt-in.\n\nCLI: `oxygen settings beta-features get`.\n\nMCP: `oxygen_settings_beta_features_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_settings_beta_features_get"],"x-oxygen-cli-command":"oxygen settings beta-features get"},"post":{"operationId":"settings.beta.set","tags":["Settings"],"summary":"Settings beta features set","description":"Enable or disable beta navigation for every workspace member; admin or owner only. Approve the preference change. This does not disable routes. 0 credits.\n\nCLI: `oxygen settings beta-features set`.\n\nMCP: `oxygen_settings_beta_features_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Show beta features in this workspace's navigation. Admin or owner required."}},"required":["enabled"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_settings_beta_features_set"],"x-oxygen-cli-command":"oxygen settings beta-features set"}},"/api/cli/settings/pages":{"get":{"operationId":"workspace_pages.get","tags":["Settings"],"summary":"List Sidebar Pages","description":"Page visibility in your own sidebar navigation menu in this workspace (Settings → Customise; only you see your choices): hidden_pages, then every page (path, name, section, parent) with hidden (you hid it) and visible (shown in your sidebar; false under a hidden section). Read-only, 0 credits.\n\nMCP: `oxygen_settings_pages_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_settings_pages_get"]},"post":{"operationId":"workspace_pages.update","tags":["Settings"],"summary":"Hide or Show Sidebar Pages","description":"Hide or show pages in your own sidebar navigation menu in this workspace (Settings → Customise): --hide Unibox,Publishing, --show Unibox, --show-all. Only your sidebar changes; teammates keep theirs. Name pages by path or name from `settings pages list`; hiding a section hides its sub-pages. Nothing is deleted and hidden pages stay reachable by URL. Free.\n\nMCP: `oxygen_settings_pages_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hide":{"type":"array","items":{"type":"string","minLength":1,"maxLength":200},"minItems":1,"maxItems":100,"description":"Pages to hide from your own sidebar, each by its path (/unibox) or name (Unibox) from the page list. Hiding a section hides its sub-pages."},"show":{"type":"array","items":{"type":"string","minLength":1,"maxLength":200},"minItems":1,"maxItems":100,"description":"Hidden pages to show again, by path or name."},"show_all":{"type":"boolean","description":"Show every page again. With hide, only those pages stay hidden."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_settings_pages_update"]}},"/api/cli/signals":{"get":{"operationId":"getSignals","tags":["Signals"],"summary":"List GTM Signal Events","description":"Lists the raw GTM signal-event feed newest-first — the typed intent events (website_visit / profile_view / post_reaction / new_follower) resolved onto the people they attached to. Unlike oxygen_signals_leads_today (a ranked, de-duplicated people queue), this is the un-ranked underlying EVENT stream: one row per event, with its type, intent weight, occurred_at, source provider, and the person (name/email/linkedin, or null when still unmatched). Narrow with types (a subset of the four) and since (look-back days). Read-only, free.\n\nMCP: `oxygen_signals_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum events to return. Defaults to 25; the plan's max (100 free to 1,000) is in oxygen_limits_show.","minimum":1,"maximum":1000}},{"name":"object","in":"query","required":false,"schema":{}},{"name":"record","in":"query","required":false,"schema":{}},{"name":"since","in":"query","required":false,"schema":{"type":"integer","description":"Look-back window in days. Defaults to 7; the plan's max (30 free to 365) is in oxygen_limits_show.","minimum":1,"maximum":365}},{"name":"types","in":"query","required":false,"schema":{"type":"array","description":"Signal types to include. Omit for all four registered types.","items":{"type":"string","enum":["website_visit","profile_view","post_engager","new_follower"]}}},{"name":"withinDays","in":"query","required":false,"schema":{}},{"name":"within_days","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_signals_list"]},"post":{"operationId":"postSignals","tags":["Signals"],"summary":"Record a GTM Signal","description":"Records one inbound GTM intent signal (website_visit / profile_view / post_engager / new_follower) into the stream by fanning it into the matching standing signal-touch automation, which asserts the person and logs a timeline activity. Internal write only — free, no approval or credit cap. Idempotent on external_event_id: pass a stable provider id (e.g. rb2b:<session>) so a redelivery dedupes. Returns the workflow_event_id so an unarmed-template drop (dispatched with zero deliveries) is observable; arm the crm-website-visitor automation first for it to land. Same code path as oxygen_crm_signal_record.\n\nMCP: `oxygen_signals_record`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","description":"Signal event. Slice 1 captures website_visit end-to-end.","enum":["website_visit","profile_view","post_engager","new_follower"]},"external_event_id":{"type":"string","description":"Stable provider event id — THE redelivery/idempotency guard. Never random.","minLength":1,"maxLength":500},"metadata":{"type":"object","description":"Optional extra dispatch metadata (provenance).","additionalProperties":true},"payload":{"type":"object","description":"Signal payload: email or linkedin_url (identity), company_domain, company_name, first_name, last_name, page_url, session_id.","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_signals_record"]}},"/api/cli/signals/registry":{"get":{"operationId":"getSignalsRegistry","tags":["Signals"],"summary":"Signal-Type Registry","description":"Shows the signal-type registry: each registered type with its human label, family, intent weight, and capture status. Every registered type is captured end-to-end today — engagement: website_visit via the RB2B de-anonymization webhook, profile_view / post_reaction / new_follower via the engagement→signal bridge; deliverability: placement_changed via the daily sender-domain placement check. Derived from code constants, not a tenant read. Read-only, free.\n\nMCP: `oxygen_signals_registry`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tag","in":"query","required":false,"schema":{"type":"string","description":"Optional workspace tag filter."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_signals_registry"]}},"/api/cli/signals/registry/{type}/tags":{"post":{"operationId":"postSignalsRegistryTypeTags","tags":["Signals"],"summary":"Tag a Definition","description":"Replaces workspace tags on one Signal type, saved Dashboard, runtime Agent, or saved Ads search. This is metadata only and never runs a provider.\n\nMCP: `oxygen_tags_attach`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"type","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"},"description":"The complete tag list; [] clears."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tags_attach"]}},"/api/cli/signals/search/plan":{"post":{"operationId":"postSignalsSearchPlan","tags":["Signals"],"summary":"Plan Signal Search","description":"Compiles a signal-sourcing request into ordered provider routes without calling a provider: the registry chain, per-route applied/dropped filters, credit estimate, table blueprint, and whether each route can be kept LIVE on a cadence.\nCOST: free. With estimate=true it additionally runs the intent's declared FREE legs — provider enum/slug resolution and, where a provider publishes one, a free match count — still zero credits.\nMATCH COUNT: read estimated_match_count.basis. Render a number ONLY for basis 'provider_count' (and name probe_tool_id); for basis 'unavailable' repeat `note` verbatim and show NO number — most signal providers publish no free count, and inventing one next to a spend decision is the failure this contract exists to prevent.\nREFUSALS: a family+scope whose default chain is deliberately empty returns refusal.code no_default_provider_chain — Oxygen does not source that by default. This is not a retryable error.\nFOLLOW-UP: _plan -> _run (dry_run) -> _run (live, approved=true, max_credits) -> oxygen_table_ingestions_wait -> oxygen_tables_preview. Unlisted wait: oxygen_capabilities_schema({names:[\"oxygen_table_ingestions_wait\"]}), then oxygen_capabilities_read with tool=oxygen_table_ingestions_wait and arguments.ingestion_run_id.\n\nMCP: `oxygen_signals_search_plan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"estimate":{"type":"boolean","description":"When true, run the FREE server-side preflight pass (zero credits): resolve provider enum values and, where one exists, a free match count."},"family":{"type":"string","description":"Signal family. hiring = open roles; tech = technology adoption; funding = financing events; acquisition = M&A; news = company news; job_change = people changing jobs; linkedin_posts = public LinkedIn posts by keyword.","enum":["hiring","tech","funding","acquisition","news","job_change","linkedin_posts"]},"filters":{"type":"object","description":"Typed signal filters. All optional; anything a route cannot apply is reported in that route's filter_application.dropped.","additionalProperties":false,"properties":{"keywords":{"type":"array","description":"Keywords: job titles for hiring, technology names for tech, topics for news; linkedin_posts: post mentions ANY.","items":{"type":"string"}},"all_keywords":{"type":"array","description":"linkedin_posts: post mentions ALL.","items":{"type":"string"}},"exclude_keywords":{"type":"array","description":"linkedin_posts: drop posts mentioning any.","items":{"type":"string"}},"sort_by":{"type":"string","enum":["recent","relevance","top"]},"min_reactions":{"type":"integer","minimum":0},"posted_by":{"type":"string","description":"linkedin_posts: author profile or company page URL."},"ai_filter":{"type":"string","description":"linkedin_posts: keep only posts AI judges to match this. Other families only if the plan has ai_filter.","maxLength":500},"countries":{"type":"array","description":"ISO 3166-1 alpha-2 country codes, uppercase (e.g. US, DE, GB).","items":{"type":"string"}},"location":{"type":"string","description":"Country or state NAME for providers that filter on a location string rather than a code."},"last_days":{"type":"integer","description":"Only signals from the last N days.","minimum":1,"maximum":3650},"domains":{"type":"array","description":"Company domains to track. Required for watch_list scope.","items":{"type":"string"}},"funding_types":{"type":"array","description":"Funding types for the funding family (e.g. series_a).","items":{"type":"string"}},"categories":{"type":"array","description":"Provider event categories.","items":{"type":"string"}},"geo":{"type":"object","description":"Countries alias if countries is absent/null; unioned with job country includes.","additionalProperties":false,"properties":{"countries":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}]}}},"job":{"type":"object","description":"Hiring only. Lists accept arrays or comma strings; values are trimmed. Titles merge with keywords; country includes merge with geo/countries, uppercase and deduplicate. last_days accepts numeric strings for integers 1–3650; differing nonblank top-level last_days is refused.","additionalProperties":false,"properties":{"title":{"type":"object","additionalProperties":false,"properties":{"include":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}]}}},"location":{"type":"object","additionalProperties":false,"properties":{"country_code":{"type":"object","additionalProperties":false,"properties":{"include":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}]}}}}},"date_posted":{"type":"object","additionalProperties":false,"properties":{"last_days":{"oneOf":[{"type":"integer","minimum":1,"maximum":3650},{"type":"string"},{"type":"null"}]}}}}},"company":{"type":"object","description":"Hiring only. Agencies are always excluded: is_agency accepts false, \"false\" or blank.","additionalProperties":false,"properties":{"is_agency":{"oneOf":[{"type":"boolean","enum":[false]},{"type":"string","enum":["false",""]},{"type":"null"}]}}}}},"goal":{},"input_shape":{},"prompt":{"type":"string","description":"Natural-language signal-sourcing request.","minLength":1,"maxLength":20000},"scope":{"type":"string","description":"market discovers new companies matching the signal; watch_list tracks the companies you name in filters.domains. Defaults per family (news and job_change default to watch_list).","enum":["market","watch_list"]},"signal_family":{},"source_prompt":{},"targetCount":{},"target_count":{"type":"number","description":"Desired rows; one Blitz query caps at 5,000 postings.","minimum":1,"maximum":10000}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_signals_search_plan"]}},"/api/cli/signals/search/preview":{"get":{"operationId":"signals.search.filters","tags":["Signals"],"summary":"Preview Professional Network Post Search","description":"Read the LinkedIn post-search filter catalog and credential status; runs no search.\n\nCLI: `oxygen signals search filters`.\n\nMCP: `oxygen_signals_search_preview`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"source","in":"query","required":false,"schema":{"type":"string","enum":["linkedin_posts"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_signals_search_preview"],"x-oxygen-cli-command":"oxygen signals search filters"},"post":{"operationId":"postSignalsSearchPreview","tags":["Signals"],"summary":"Preview Professional Network Post Search","description":"linkedin_posts only: list the post-search filters, or preview public LinkedIn posts FREE (up to 25 per keyword) with author, engagement and the optional ai_filter applied. Nothing is created or charged. Then oxygen_signals_search_run with family=linkedin_posts and the same filters: dry_run, then live with approved=true, plus max_credits if the dry run quotes ai_filter reasons.\n\nMCP: `oxygen_signals_search_preview`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"credentialMode":{},"credential_mode":{"type":"string","enum":["managed","user_api_key"],"description":"user_api_key: your own Up2Data key from Connections."},"family":{},"filters":{"type":"object","description":"Typed signal filters. All optional; anything a route cannot apply is reported in that route's filter_application.dropped.","additionalProperties":false,"properties":{"keywords":{"type":"array","description":"Keywords: job titles for hiring, technology names for tech, topics for news; linkedin_posts: post mentions ANY.","items":{"type":"string"}},"all_keywords":{"type":"array","description":"linkedin_posts: post mentions ALL.","items":{"type":"string"}},"exclude_keywords":{"type":"array","description":"linkedin_posts: drop posts mentioning any.","items":{"type":"string"}},"sort_by":{"type":"string","enum":["recent","relevance","top"]},"min_reactions":{"type":"integer","minimum":0},"posted_by":{"type":"string","description":"linkedin_posts: author profile or company page URL."},"ai_filter":{"type":"string","description":"linkedin_posts: keep only posts AI judges to match this. Other families only if the plan has ai_filter.","maxLength":500},"countries":{"type":"array","description":"ISO 3166-1 alpha-2 country codes, uppercase (e.g. US, DE, GB).","items":{"type":"string"}},"location":{"type":"string","description":"Country or state NAME for providers that filter on a location string rather than a code."},"last_days":{"type":"integer","description":"Only signals from the last N days.","minimum":1,"maximum":3650},"domains":{"type":"array","description":"Company domains to track. Required for watch_list scope.","items":{"type":"string"}},"funding_types":{"type":"array","description":"Funding types for the funding family (e.g. series_a).","items":{"type":"string"}},"categories":{"type":"array","description":"Provider event categories.","items":{"type":"string"}}}},"source":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_signals_search_preview"]}},"/api/cli/signals/search/run":{"post":{"operationId":"postSignalsSearchRun","tags":["Signals"],"summary":"Run Signal Search","description":"Returns a dry-run request or queues a live table ingestion run for one signal-search route, creating the table from the plan blueprint when none is passed.\nCOST: dry_run is free; live consumes credits within max_credits and requires approved=true. linkedin_posts is free (approved=true only) unless the dry run quotes credits for ai_filter reasons or an ai_filter block.\nLIVE TABLE: pass bind_feed=true with every to also bind a pull feed to the same table in the same call, so it keeps refilling on a cadence. That is a STANDING spend grant and is refused (feed_not_incremental) when the chosen provider cannot resume where it left off.\nFOLLOW-UP: oxygen_signals_search_run (mode=live) -> oxygen_table_ingestions_wait -> oxygen_tables_preview -> oxygen_feeds_get. Unlisted wait: oxygen_capabilities_schema({names:[\"oxygen_table_ingestions_wait\"]}), then oxygen_capabilities_read with tool=oxygen_table_ingestions_wait and arguments.ingestion_run_id.\n\nMCP: `oxygen_signals_search_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required for live runs after inspecting dry-run output."},"bind_feed":{"type":"boolean","description":"Also bind a pull feed to the target table so it keeps refilling. Requires every."},"credential_mode":{"type":"string","enum":["managed","user_api_key"],"description":"linkedin_posts: user_api_key runs on your Up2Data key from Connections."},"every":{"type":"string","description":"Feed cadence: hourly, every_6h, daily@<hour>, or weekly@<day><hour>. Hours are 0-23 UTC."},"family":{"type":"string","description":"Signal family. hiring = open roles; tech = technology adoption; funding = financing events; acquisition = M&A; news = company news; job_change = people changing jobs; linkedin_posts = public LinkedIn posts by keyword.","enum":["hiring","tech","funding","acquisition","news","job_change","linkedin_posts"]},"filters":{"type":"object","description":"Typed signal filters. All optional; anything a route cannot apply is reported in that route's filter_application.dropped.","additionalProperties":false,"properties":{"keywords":{"type":"array","description":"Keywords: job titles for hiring, technology names for tech, topics for news; linkedin_posts: post mentions ANY.","items":{"type":"string"}},"all_keywords":{"type":"array","description":"linkedin_posts: post mentions ALL.","items":{"type":"string"}},"exclude_keywords":{"type":"array","description":"linkedin_posts: drop posts mentioning any.","items":{"type":"string"}},"sort_by":{"type":"string","enum":["recent","relevance","top"]},"min_reactions":{"type":"integer","minimum":0},"posted_by":{"type":"string","description":"linkedin_posts: author profile or company page URL."},"ai_filter":{"type":"string","description":"linkedin_posts: keep only posts AI judges to match this. Other families only if the plan has ai_filter.","maxLength":500},"countries":{"type":"array","description":"ISO 3166-1 alpha-2 country codes, uppercase (e.g. US, DE, GB).","items":{"type":"string"}},"location":{"type":"string","description":"Country or state NAME for providers that filter on a location string rather than a code."},"last_days":{"type":"integer","description":"Only signals from the last N days.","minimum":1,"maximum":3650},"domains":{"type":"array","description":"Company domains to track. Required for watch_list scope.","items":{"type":"string"}},"funding_types":{"type":"array","description":"Funding types for the funding family (e.g. series_a).","items":{"type":"string"}},"categories":{"type":"array","description":"Provider event categories.","items":{"type":"string"}},"geo":{"type":"object","description":"Countries alias if countries is absent/null; unioned with job country includes.","additionalProperties":false,"properties":{"countries":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}]}}},"job":{"type":"object","description":"Hiring only. Lists accept arrays or comma strings; values are trimmed. Titles merge with keywords; country includes merge with geo/countries, uppercase and deduplicate. last_days accepts numeric strings for integers 1–3650; differing nonblank top-level last_days is refused.","additionalProperties":false,"properties":{"title":{"type":"object","additionalProperties":false,"properties":{"include":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}]}}},"location":{"type":"object","additionalProperties":false,"properties":{"country_code":{"type":"object","additionalProperties":false,"properties":{"include":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"},{"type":"null"}]}}}}},"date_posted":{"type":"object","additionalProperties":false,"properties":{"last_days":{"oneOf":[{"type":"integer","minimum":1,"maximum":3650},{"type":"string"},{"type":"null"}]}}}}},"company":{"type":"object","description":"Hiring only. Agencies are always excluded: is_agency accepts false, \"false\" or blank.","additionalProperties":false,"properties":{"is_agency":{"oneOf":[{"type":"boolean","enum":[false]},{"type":"string","enum":["false",""]},{"type":"null"}]}}}}},"max_credits":{"type":"number","description":"Credit ceiling for live runs; linkedin_posts: only if the dry run quotes one.","minimum":0},"max_credits_per_cycle":{"type":"number","description":"Credit ceiling PER sync cycle for the bound feed.","minimum":0},"max_pages":{"type":"integer","description":"Pages to ingest; Blitz jobs auto-page up to 100, others default to 1.","minimum":1,"maximum":100},"max_rows_per_cycle":{"type":"integer","description":"Advisory row ceiling per sync cycle for the bound feed.","minimum":1},"mode":{"type":"string","description":"dry_run (default, free) or live.","enum":["dry_run","live"]},"plan":{"type":"object","description":"Plan returned by oxygen_signals_search_plan.","additionalProperties":true},"project":{"type":"string","description":"Folder id or slug for the created table; ignored with `table`.","maxLength":200},"prompt":{"type":"string","description":"Natural-language signal-sourcing request. Pass prompt (with family) or plan; linkedin_posts needs only filters.","minLength":1,"maxLength":20000},"route_id":{"type":"string","description":"Route id from the plan to execute.","maxLength":200},"scope":{"type":"string","description":"market discovers new companies matching the signal; watch_list tracks the companies you name in filters.domains. Defaults per family (news and job_change default to watch_list).","enum":["market","watch_list"]},"source":{"type":"string","enum":["linkedin_posts"],"description":"Native post-search lane using filters; no prompt needed."},"table":{"type":"string","description":"Existing table id or slug to receive rows. If omitted for live, Oxygen creates one from the plan blueprint.","maxLength":400},"target_count":{"type":"number","description":"Desired rows; one Blitz query caps at 5,000 postings.","minimum":1,"maximum":10000},"tool_id":{"type":"string","description":"Tool id from the plan to execute.","maxLength":200},"upsert_key":{"type":"string","description":"Column key used for live upsert. Defaults to the plan upsert key.","maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_signals_search_run"]}},"/api/cli/signup-leads/deliveries":{"get":{"operationId":"getSignupLeadsDeliveries","tags":["Signup leads"],"summary":"List Signup Lead Deliveries","description":"Lists durable signup lead webhook deliveries for the current organization, including retry/error state.\n\nMCP: `oxygen_signup_lead_deliveries_list`, `oxygen_signup_lead_delivery_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"event_id","in":"query","required":false,"schema":{}},{"name":"id","in":"query","required":false,"schema":{}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum deliveries to return. Defaults to 50.","minimum":1,"maximum":200}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Optional status filter: pending, running, succeeded, skipped, retrying, failed, or dead."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_signup_lead_deliveries_list","oxygen_signup_lead_delivery_get"]},"post":{"operationId":"postSignupLeadsDeliveries","tags":["Signup leads"],"summary":"Retry Signup Lead Delivery","description":"Queues a failed signup lead webhook delivery for retry by delivery id or event id.\n\nMCP: `oxygen_signup_lead_delivery_retry`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"event_id":{"type":"string","description":"Explicit signup lead event id. Use this when the event id could be UUID-shaped.","minLength":1},"id":{"type":"string","description":"Signup lead delivery id or event id.","minLength":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_signup_lead_delivery_retry"]}},"/api/cli/skills/get":{"get":{"operationId":"skills.get","tags":["Skills"],"summary":"Skills get","description":"Read one authenticated, entitled product-skill entrypoint or manifest-listed supporting file.\n\nMCP: `oxygen_skills_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"name","in":"query","required":true,"schema":{"type":"string"}},{"name":"file","in":"query","required":false,"schema":{"type":"string","description":"Relative supporting-file path from the manifest; omit for SKILL.md."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_skills_get"]}},"/api/cli/skills/workspace/archive":{"post":{"operationId":"workspace_skills.archive","tags":["Skills"],"summary":"Workspace skills: archive","description":"Archive a workspace skill, retaining files and Knowledge history; 0 credits, no inference/provider calls or new tool/spend/approval authority. Requires the entrypoint's expected revision; removes it from discovery.\n\nCLI: `oxygen skills workspace archive`.\n\nMCP: `oxygen_workspace_skills_archive`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Exact workspace skill name returned by list or import (workspace-…)."},"expected_revision":{"type":"integer","minimum":1,"description":"Entrypoint revision last read; stale revisions refuse."}},"required":["name","expected_revision"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workspace_skills_archive"],"x-oxygen-cli-command":"oxygen skills workspace archive"}},"/api/cli/skills/workspace/create":{"post":{"operationId":"workspace_skills.create","tags":["Skills"],"summary":"Workspace skills: create","description":"Create workspace-<name>, visible to this workspace's members; 0 credits, no inference/provider calls or new tool/spend/approval authority. Creates SKILL.md in Knowledge from a lowercase-hyphen name, description and instructions.\n\nMCP: `oxygen_workspace_skills_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":64,"description":"Lowercase-hyphen name; stored as workspace-<name>."},"description":{"type":"string","minLength":1,"maxLength":1024},"instructions":{"type":"string","minLength":1,"maxLength":120000}},"required":["name","description","instructions"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workspace_skills_create"]}},"/api/cli/skills/workspace/get":{"get":{"operationId":"workspace_skills.get","tags":["Skills"],"summary":"Workspace skills: get","description":"Read a workspace skill's SKILL.md or one supporting text file, with exact content, revision and the document index. Skills are task guidance; they grant no tool, spend or approval authority.\n\nCLI: `oxygen skills workspace get`.\n\nMCP: `oxygen_workspace_skills_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"name","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Exact workspace skill name returned by list or import (workspace-…)."}},{"name":"file","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":240,"description":"Relative file path; defaults to SKILL.md."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_skills_get"],"x-oxygen-cli-command":"oxygen skills workspace get"}},"/api/cli/skills/workspace/import":{"post":{"operationId":"workspace_skills.import","tags":["Skills"],"summary":"Workspace skills: import","description":"Import to workspace members atomically, create-only; ≤50 text files/1 MB; scripts inert; 0 credits, no inference/paid provider calls or new tool/spend/approval authority. Supply root SKILL.md plus supporting text files, or a public HTTPS SKILL.md URL. Preserves content and source. CLI accepts --file, --directory or --url.\n\nMCP: `oxygen_workspace_skills_import`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":64},"files":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"path":{"type":"string","minLength":1,"maxLength":240,"description":"Relative file path; defaults to SKILL.md."},"content":{"type":"string","maxLength":120000}},"required":["path","content"]},"minItems":1,"maxItems":50},"url":{"type":"string","maxLength":2000,"description":"Public HTTPS SKILL.md URL (raw text or GitHub file). Choose url or files. A URL imports the entrypoint only; supply files for a complete folder."},"source_url":{"type":"string","maxLength":2000,"description":"Optional HTTPS origin for provenance. Content must be supplied; this does not fetch the URL."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workspace_skills_import"]}},"/api/cli/skills/workspace/list":{"get":{"operationId":"workspace_skills.list","tags":["Skills"],"summary":"Workspace skills: list","description":"Find skills shared with workspace members by literal substring of name or description; short keywords work best; read-only, 0 credits; next_cursor continues the list.\n\nCLI: `oxygen skills workspace list`.\n\nMCP: `oxygen_workspace_skills_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"query","in":"query","required":false,"schema":{"type":"string","description":"Case-insensitive literal substring of the name or description; short keywords work best."}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","description":"Exact next_cursor from the previous list response."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"description":"Skills per page, from 1 to 100."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_skills_list"],"x-oxygen-cli-command":"oxygen skills workspace list"}},"/api/cli/skills/workspace/update":{"post":{"operationId":"workspace_skills.update","tags":["Skills"],"summary":"Workspace skills: update","description":"Replace a skill file at its expected revision; read first, stale revisions refuse; 0 credits, no inference/provider calls or new tool/spend/approval authority. Preserves Knowledge history; defaults to SKILL.md.\n\nCLI: `oxygen skills workspace update`.\n\nMCP: `oxygen_workspace_skills_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Exact workspace skill name returned by list or import (workspace-…)."},"file":{"type":"string","minLength":1,"maxLength":240,"description":"Relative file path; defaults to SKILL.md."},"content":{"type":"string","maxLength":120000,"description":"Full replacement file; SKILL.md must include YAML frontmatter. Its description drives discovery."},"expected_revision":{"type":"integer","minimum":1,"description":"Revision last read; a stale revision refuses the edit."}},"required":["name","content","expected_revision"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workspace_skills_update"],"x-oxygen-cli-command":"oxygen skills workspace update"}},"/api/cli/sourcing/plan":{"post":{"operationId":"postSourcingPlan","tags":["Sourcing"],"summary":"Plan Sourcing","description":"Classifies account, people, profile, or enrichment-handoff sourcing requests into an Oxygen strategy with runnable provider routes, cost posture, approval gates, and next commands. Planning does not execute paid providers. The account-finding step delegates to oxygen_companies_search_plan/run — run company search there to build the account list.\n\nMCP: `oxygen_sourcing_plan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"materializePreview":{},"materialize_preview":{"type":"boolean","description":"When true, create an Oxygen preview table for the plan. Defaults to false."},"prompt":{"type":"string","description":"Natural-language sourcing goal, including account/person constraints and desired enrichment handoff.","minLength":1,"maxLength":20000},"source_prompt":{},"strategy":{"type":"string","description":"Optional strategy id, such as account_first_lead_sourcing, known_account_org_chart, or phone_ready_contact_sourcing."},"table":{},"targetTableId":{},"target_table_id":{"type":"string","description":"Optional target table id or slug for follow-up commands."},"useCase":{},"use_case":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_sourcing_plan"]}},"/api/cli/spintax":{"post":{"operationId":"spintax.generate","tags":["Spintax"],"summary":"Spintax generate","description":"Generate wording or copy variations as spintax: live (default) costs 3 credits and requires approval and a credit ceiling; explicit dry_run is a free preview. Preserve merge variables; send nothing. Live requires approved:true and max_credits>=3 after preview; failed generation refunds the reservation.\n\nCLI: `oxygen spintax generate`.\n\nMCP: `oxygen_spintax_generate`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":4000,"description":"Outreach copy to vary; merge variables are preserved."},"section":{"type":"string","maxLength":80,"description":"Optional section label, e.g. Subject."},"approved":{"type":"boolean","description":"True only after approval of the exact text and 3-credit cost."},"max_credits":{"type":"number","minimum":0,"description":"Live ceiling must cover the fixed 3-credit cost."}},"required":["text"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_spintax_generate"],"x-oxygen-cli-command":"oxygen spintax generate"}},"/api/cli/subscriptions":{"get":{"operationId":"getSubscriptions","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"email","in":"query","required":false,"schema":{"type":"string","description":"get/set/contact_*."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]},"post":{"operationId":"postSubscriptions","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"get/set/contact_*."},"evidence":{"type":"object","properties":{"notice_version":{"type":"string"},"notice_text_hash":{"type":"string","description":"sha256 hex of the notice text shown."},"form_url":{"type":"string"},"basis":{"type":"string","description":"Where consent came from."}},"description":"set/import/contact_add: consent evidence."},"list":{"type":"string","description":"List key or id (update_list/set/import/contact_*/contacts/export)."},"source":{"type":"string","description":"set/import (import requires it)/contact_add: where it came from."},"status":{"type":"string","enum":["subscribed","unsubscribed","pending","cleaned"],"description":"set; contacts filter; import/contact_add default subscribed."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]}},"/api/cli/subscriptions/contacts":{"get":{"operationId":"getSubscriptionsContacts","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]},"post":{"operationId":"postSubscriptionsContacts","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"get/set/contact_*."},"evidence":{"type":"object","properties":{"notice_version":{"type":"string"},"notice_text_hash":{"type":"string","description":"sha256 hex of the notice text shown."},"form_url":{"type":"string"},"basis":{"type":"string","description":"Where consent came from."}},"description":"set/import/contact_add: consent evidence."},"first_name":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"contact_add/edit; null clears."},"last_name":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"contact_add/edit; null clears."},"list":{"type":"string","description":"List key or id (update_list/set/import/contact_*/contacts/export)."},"note":{"type":"string","description":"contact_add: how consent was given; recorded as the basis."},"properties":{"type":"object","description":"contact_add/edit: property key -> value; null clears."},"source":{"type":"string","description":"set/import (import requires it)/contact_add: where it came from."},"status":{"type":"string","enum":["subscribed","unsubscribed","pending","cleaned"],"description":"set; contacts filter; import/contact_add default subscribed."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]},"patch":{"operationId":"patchSubscriptionsContacts","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"get/set/contact_*."},"first_name":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"contact_add/edit; null clears."},"last_name":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"contact_add/edit; null clears."},"list":{"type":"string","description":"List key or id (update_list/set/import/contact_*/contacts/export)."},"properties":{"type":"object","description":"contact_add/edit: property key -> value; null clears."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]},"delete":{"operationId":"deleteSubscriptionsContacts","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]}},"/api/cli/subscriptions/contacts/export":{"get":{"operationId":"getSubscriptionsContactsExport","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]}},"/api/cli/subscriptions/import":{"post":{"operationId":"postSubscriptionsImport","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"person_id":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"properties":{"type":"object"}},"required":["email"]},"description":"import; at most 1,000 per call when entries carry names or properties."},"evidence":{"type":"object","properties":{"notice_version":{"type":"string"},"notice_text_hash":{"type":"string","description":"sha256 hex of the notice text shown."},"form_url":{"type":"string"},"basis":{"type":"string","description":"Where consent came from."}},"description":"set/import/contact_add: consent evidence."},"list":{"type":"string","description":"List key or id (update_list/set/import/contact_*/contacts/export)."},"source":{"type":"string","description":"set/import (import requires it)/contact_add: where it came from."},"status":{"type":"string","enum":["subscribed","unsubscribed","pending","cleaned"],"description":"set; contacts filter; import/contact_add default subscribed."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]}},"/api/cli/subscriptions/lists":{"get":{"operationId":"getSubscriptionsLists","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]},"post":{"operationId":"postSubscriptionsLists","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"default_subscription":{"type":"string","enum":["opt_in","opt_out"],"description":"*_list, topics."},"description":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"*_list; null clears."},"key":{"type":"string","description":"create_list: e.g. newsletter. property_*: field key."},"kind":{"type":"string","enum":["marketing","product_updates","onboarding","topic"],"description":"*_list."},"name":{"type":"string","description":"*_list."},"parent":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"*_list: a topic's audience list; null clears."},"visibility":{"type":"string","enum":["public","private"],"description":"*_list: private hides it from non-subscribers' preference page."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]},"patch":{"operationId":"patchSubscriptionsLists","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"default_subscription":{"type":"string","enum":["opt_in","opt_out"],"description":"*_list, topics."},"description":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"*_list; null clears."},"kind":{"type":"string","enum":["marketing","product_updates","onboarding","topic"],"description":"*_list."},"list":{"type":"string","description":"List key or id (update_list/set/import/contact_*/contacts/export)."},"name":{"type":"string","description":"*_list."},"parent":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"*_list: a topic's audience list; null clears."},"visibility":{"type":"string","enum":["public","private"],"description":"*_list: private hides it from non-subscribers' preference page."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]}},"/api/cli/subscriptions/properties":{"get":{"operationId":"getSubscriptionsProperties","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]},"post":{"operationId":"postSubscriptionsProperties","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"create_list: e.g. newsletter. property_*: field key."},"label":{"type":"string","description":"property_create/update."},"type":{"type":"string","enum":["string","number"],"description":"property_create (default string)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]},"patch":{"operationId":"patchSubscriptionsProperties","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"create_list: e.g. newsletter. property_*: field key."},"label":{"type":"string","description":"property_create/update."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]},"delete":{"operationId":"deleteSubscriptionsProperties","tags":["Subscriptions"],"summary":"Subscriptions","description":"Subscription lists, contacts and consent for bulk email; sending-domain Sequences send only to subscribed addresses on their list. A topic (kind=topic, parent=audience list) gets only its own subscribers; opt_out topics are joined with the parent. action=lists (default), create_list, update_list, get (one email's statuses), set (one email on one list), import (up to 5,000 under one evidence record; entries may carry first_name, last_name, properties), contacts (page a list; search email or name), contact_add, contact_edit, contact_remove (subscribed/pending only; consent history kept), export, properties, property_create|update|delete. A contact's name and properties live on its Records People record ({{contact.<key>}} in copy). Subscribing needs evidence: notice_version with notice_text_hash, or basis (contact_add: note). An unsubscribed or cleaned address stays so: set and contact_add refuse (409, do not retry), import counts it (kept_unsubscribed, kept_cleaned); only they can rejoin, from the preference page linked in any newsletter they received. 0 credits.\n\nMCP: `oxygen_subscriptions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"key","in":"query","required":false,"schema":{"type":"string","description":"create_list: e.g. newsletter. property_*: field key."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_subscriptions"]}},"/api/cli/supabase/catalog":{"post":{"operationId":"postSupabaseCatalog","tags":["Supabase"],"summary":"Inspect Supabase Catalog","description":"Reads the saved read-only Supabase connection and lists accessible base tables, columns, mapped Oxygen types, primary keys, and estimated rows. Managed/system schemas are excluded. External read only; 0 credits.\n\nMCP: `oxygen_supabase_catalog`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{},"connection_id":{"type":"string","description":"Supabase connection id. Omit for the workspace default."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_supabase_catalog"]}},"/api/cli/supabase/imports":{"post":{"operationId":"postSupabaseImports","tags":["Supabase"],"summary":"Start Supabase Import","description":"Starts the exact previewed selection as durable Postgres-backed table ingestion. Creates one Oxygen Table per new source; refresh upserts primary-keyed rows, preserves Oxygen-authored columns, and marks missing source rows instead of deleting them. Keyless tables permit only one snapshot. External read plus Oxygen writes; 0 credits.\n\nMCP: `oxygen_supabase_import_start`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"catalogFingerprint":{},"catalog_fingerprint":{"type":"string","description":"SHA-256 fingerprint returned by oxygen_supabase_import_plan.","minLength":64,"maxLength":64},"connectionId":{},"connection_id":{"type":"string","description":"Supabase connection id. Omit for the workspace default."},"project":{"type":"string","description":"Optional Oxygen project/folder id or slug for newly created Tables."},"projectId":{},"project_id":{},"selection":{},"tables":{"type":"array","description":"Supabase base tables to import.","minItems":1,"maxItems":50,"items":{"type":"object","additionalProperties":false,"properties":{"schema":{"type":"string","minLength":1,"maxLength":63},"table":{"type":"string","minLength":1,"maxLength":63}},"required":["schema","table"]}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_supabase_import_start"]}},"/api/cli/supabase/imports/{importId}":{"get":{"operationId":"getSupabaseImportsImportId","tags":["Supabase"],"summary":"Get Supabase Import","description":"Returns aggregate and per-table status, row counts, failures, and deep-links for a durable Supabase import. Read-only; 0 credits.\n\nMCP: `oxygen_supabase_import_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_supabase_import_get"]}},"/api/cli/supabase/imports/{importId}/cancel":{"post":{"operationId":"postSupabaseImportsImportIdCancel","tags":["Supabase"],"summary":"Cancel Supabase Import","description":"Requests cancellation of every still-active child table run in a Supabase import. Does not delete rows already imported and never writes to Supabase.\n\nMCP: `oxygen_supabase_import_cancel`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_supabase_import_cancel"]}},"/api/cli/supabase/imports/{importId}/retry":{"post":{"operationId":"postSupabaseImportsImportIdRetry","tags":["Supabase"],"summary":"Retry Supabase Import","description":"Retries failed child table items. Primary-keyed upserts make already-written source rows safe; 0 credits.\n\nMCP: `oxygen_supabase_import_retry`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_supabase_import_retry"]}},"/api/cli/supabase/imports/plan":{"post":{"operationId":"postSupabaseImportsPlan","tags":["Supabase"],"summary":"Preview Supabase Import","description":"Previews one Oxygen Table per selected Supabase table, exact create/refresh behavior, row-limit posture, deletion marking, and a schema fingerprint. Charges 0 credits. Call before oxygen_supabase_import_start.\n\nMCP: `oxygen_supabase_import_plan`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{},"connection_id":{"type":"string","description":"Supabase connection id. Omit for the workspace default."},"selection":{},"tables":{"type":"array","description":"Supabase base tables to import.","minItems":1,"maxItems":50,"items":{"type":"object","additionalProperties":false,"properties":{"schema":{"type":"string","minLength":1,"maxLength":63},"table":{"type":"string","minLength":1,"maxLength":63}},"required":["schema","table"]}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_supabase_import_plan"]}},"/api/cli/support/tickets":{"get":{"operationId":"getSupportTickets","tags":["Support"],"summary":"List Support Tickets","description":"List Plain support Threads scoped to the active OXYGEN organization.\n\nMCP: `oxygen_support_tickets_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_support_tickets_list"]},"post":{"operationId":"postSupportTickets","tags":["Support"],"summary":"File a Support Ticket","description":"Opens a Plain support conversation with a required message and optional subject. Real zero-credit write; no preview. Show the exact body, optional subject, context and attachment and obtain customer confirmation. Omit subject for ordinary chat; the API derives it. Add run/table IDs and deep-links; open duplicates are deduplicated.\n\nMCP: `oxygen_support_ticket_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":20000,"description":"Required customer message: goal, observed behavior, and attempts made. This becomes the opening Plain message."},"category":{"type":"string","enum":["question","bug","feature_request","billing","security_data","configuration","agency_directory","other"],"description":"Stable request type used for Plain triage."},"context":{"type":"object","description":"Relevant diagnostic context.","properties":{"operation":{"type":"string","description":"Failed operation."},"error_code":{"type":"string","description":"Error envelope code."},"run_ids":{"type":"array","items":{"type":"string"},"maxItems":20},"table_ids":{"type":"array","items":{"type":"string"},"maxItems":20},"deep_links":{"type":"array","items":{"type":"string"},"maxItems":20,"description":"Affected OXYGEN run/Table URLs."},"cli_version":{"type":"string"},"slack_permalink":{"type":"string","maxLength":500,"description":"Selected Slack message permalink."},"slack_channel_id":{"type":"string","maxLength":64,"description":"e.g. C0123ABC456 — where a forwarded report came from."},"customer_workspace":{"type":"string","maxLength":200,"description":"Reported workspace name or slug."}},"additionalProperties":false},"message":{},"severity":{"type":"string","enum":["low","normal","high"],"description":"Defaults to normal."},"source":{"type":"string","enum":["slack"],"description":"Where the report originated outside the product."},"subject":{"type":"string","minLength":1,"maxLength":240,"description":"One-line summary of the problem."},"transcript":{"type":"object","description":"Customer-selected gzip/base64 transcript, instead of transcript_text.","properties":{"content_b64":{"type":"string","minLength":1,"maxLength":4000000},"source":{"type":"string","enum":["claude_code","codex","cursor","file","unknown"]},"session_id":{"type":"string"},"tool":{"type":"string"},"event_count":{"type":"number","minimum":0},"byte_size":{"type":"number","minimum":0},"format":{"type":"string","enum":["jsonl.gz.b64"]},"truncated":{"type":"boolean"}},"required":["content_b64"],"additionalProperties":false},"transcript_text":{"type":"string","maxLength":200000,"description":"Optional customer-approved conversation excerpt. Send only the selected relevant text; credentials are redacted again by the API."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_support_ticket_create"]}},"/api/cli/support/tickets/{ticketId}":{"get":{"operationId":"getSupportTicketsTicketId","tags":["Support"],"summary":"Get a Support Ticket","description":"Fetch one Plain support Thread with its customer-visible message timeline.\n\nMCP: `oxygen_support_ticket_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"ticketId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_support_ticket_get"]}},"/api/cli/support/tickets/{ticketId}/messages":{"post":{"operationId":"postSupportTicketsTicketIdMessages","tags":["Support"],"summary":"Reply to a Support Ticket","description":"Reply to a Plain Chat thread as its original customer. For migrated archives or native Slack threads, this safely opens or continues one linked Chat thread instead of sending through the original channel. Requires Plain headless-portal support.\n\nMCP: `oxygen_support_ticket_reply`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"ticketId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":20000,"description":"Your reply."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_support_ticket_reply"]}},"/api/cli/suppressions":{"get":{"operationId":"getSuppressions","tags":["Suppressions"],"summary":"List Contact Suppressions","description":"Lists the org do-not-contact entries, newest first; enrollment skips, and each step rechecks, a lead whose provider id or normalized LinkedIn profile URL equals one. A URL entry matches a lead's profile URL only in the form https://www.linkedin.com/in/<lowercase handle>. A WhatsApp reply's entry holds its WhatsApp id, which WhatsApp leads rarely carry. Filter by reason or by a case-insensitive substring of the lead provider id. Rows carry identity {name, pictureUrl, profileUrl} when the workspace knows the person. Consumes 0 credits.\n\nMCP: `oxygen_suppressions_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum suppressions to return (1-500; default 100)."}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","description":"Pagination offset (0-based)."}},{"name":"reason","in":"query","required":false,"schema":{"type":"string","enum":["manual","replied","unsubscribed","bounced","do_not_contact","friends"],"description":"Filter by reason."}},{"name":"search","in":"query","required":false,"schema":{"type":"string","description":"Case-insensitive substring match on the lead provider id."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_suppressions_list"]},"post":{"operationId":"postSuppressions","tags":["Suppressions"],"summary":"Add Contact Suppression","description":"Adds or refreshes selected lead provider ids on the org DNC list; enrollment skips, and each step rechecks, a lead whose provider id or normalized LinkedIn profile URL equals one. Ids are stored as typed, so a URL matches only as https://www.linkedin.com/in/<lowercase handle>. Choose lead_provider_id or lead_provider_ids (1-500). Idempotent; reason defaults to manual. 0 credits.\n\nMCP: `oxygen_suppressions_add`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string","description":"Optional free-text note stored with the suppression."},"leadProviderId":{},"lead_provider_id":{"type":"string","description":"The lead provider id (e.g. a LinkedIn ACo... id) to suppress."},"lead_provider_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500,"description":"Exact batch; exclusive with lead_provider_id."},"reason":{"type":"string","enum":["manual","replied","unsubscribed","bounced","do_not_contact","friends"],"description":"Why the lead is suppressed; defaults to 'manual'."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_suppressions_add"]},"delete":{"operationId":"deleteSuppressions","tags":["Suppressions"],"summary":"Remove Contact Suppression","description":"Removes selected lead ids or every identity of selected subject ids from the org DNC list. Choose one singular selector or a 1-500 item array. 0 credits.\n\nMCP: `oxygen_suppressions_remove`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"leadProviderId","in":"query","required":false,"schema":{}},{"name":"lead_provider_id","in":"query","required":false,"schema":{"type":"string","description":"Lead provider id to un-suppress."}},{"name":"lead_provider_ids","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500}},{"name":"subjectId","in":"query","required":false,"schema":{}},{"name":"subject_id","in":"query","required":false,"schema":{"type":"string","description":"A merged person's metadata.dnc_subject_id."}},{"name":"subject_ids","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_suppressions_remove"]}},"/api/cli/suppressions/addresses":{"get":{"operationId":"getSuppressionsAddresses","tags":["Suppressions"],"summary":"List Blocked Email Addresses","description":"Read blocked email addresses (bounces, unsubscribes and imports), newest first, with matching CRM identities. MCP defaults to bounded summary pages; follow paging.next_offset with the same reason/search filters. Summary omits detail and metadata; view:full keeps them. 0 credits.\n\nMCP: `oxygen_suppressions_addresses_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"description":"Page size, 1-500; API default 100."}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Current-ledger offset; repeat the same filters. Concurrent changes may shift rows."}},{"name":"reason","in":"query","required":false,"schema":{"type":"string","enum":["hard_bounce","complaint","unsubscribe","manual"]}},{"name":"search","in":"query","required":false,"schema":{"type":"string","description":"Case-insensitive address substring."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_suppressions_addresses_list"]},"delete":{"operationId":"suppressions.addresses.remove","tags":["Suppressions"],"summary":"Suppressions remove address","description":"Remove one email-address sending block or up to 500 exact addresses after approval of the keys. Can restore future sending eligibility; other suppression ledgers still apply. This does not resume enrollments automatically. 0 credits.\n\nMCP: `oxygen_suppressed_addresses_remove`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","minLength":1,"description":"One full email address. Supply email or emails, never both."},"emails":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500,"description":"Addresses to unblock. Supply emails or email, never both."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_suppressed_addresses_remove"]}},"/api/cli/suppressions/companies":{"get":{"operationId":"getSuppressionsCompanies","tags":["Suppressions"],"summary":"List Company Suppressions","description":"Lists explicit company-domain or LinkedIn-company DNC identities. These stop every Sequence channel and are never inferred from a contact email. 0 credits.\n\nMCP: `oxygen_suppressions_companies_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["domain","linkedin_company"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"reason","in":"query","required":false,"schema":{"type":"string","enum":["manual","complaint","policy","do_not_contact"]}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_suppressions_companies_list"]},"delete":{"operationId":"deleteSuppressionsCompanies","tags":["Suppressions"],"summary":"Remove Company Suppression","description":"Deliberately re-enables one explicit company-domain or LinkedIn-company identity. 0 credits.\n\nMCP: `oxygen_suppressions_company_remove`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"identities","in":"query","required":false,"schema":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["domain","linkedin_company"]},"value":{"type":"string"}},"required":["kind","value"],"additionalProperties":false},"minItems":1,"maxItems":500}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["domain","linkedin_company"]}},{"name":"value","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_suppressions_company_remove"]}},"/api/cli/suppressions/crm-backfill":{"post":{"operationId":"postSuppressionsCrmBackfill","tags":["Suppressions"],"summary":"File DNC People Into the CRM","description":"Creates CRM person records for people already on the do-not-contact list. New suppressions do this on their own; this covers earlier ones. Previews unless live is true; pages via offset/next_offset. Runs no enrichment, so 0 credits.\n\nMCP: `oxygen_suppressions_crm_backfill`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":500},"live":{"type":"boolean"},"offset":{"type":"integer","minimum":0}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_suppressions_crm_backfill"]}},"/api/cli/suppressions/domains":{"get":{"operationId":"suppressions.domains.list","tags":["Suppressions"],"summary":"Suppressions domains","description":"Read domain-wide sending blocks, newest first. Domain reasons differ from address reasons. MCP defaults to bounded summary pages; follow paging.next_offset with the same filters. 0 credits.\n\nMCP: `oxygen_suppressed_domains_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"reason","in":"query","required":false,"schema":{"type":"string","enum":["manual","complaint","policy"]}},{"name":"search","in":"query","required":false,"schema":{"type":"string","description":"Case-insensitive bare-domain substring."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"x-clamp":true,"description":"Page size, 1-500; API default 100."}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Current-ledger offset; repeat the same filters. Concurrent changes may shift rows."}},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["full","summary"],"description":"Full keeps native fields; summary names omitted evidence fields in projection. HTTP/CLI default full."}},{"name":"max_chars","in":"query","required":false,"schema":{"type":"integer","minimum":2000,"maximum":40000,"description":"Native context window; MCP caps it at 10000 (external) or 4000 (built-in). Paging.next_offset follows the last exposed row."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_suppressed_domains_list"]},"delete":{"operationId":"suppressions.domains.remove","tags":["Suppressions"],"summary":"Suppressions remove domain","description":"Remove one domain-wide sending block or up to 500 exact domains after approval of the keys. Can restore future sending eligibility; other suppression ledgers still apply. This does not resume enrollments automatically. 0 credits.\n\nMCP: `oxygen_suppressed_domains_remove`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","minLength":1,"description":"One bare domain, e.g. acme.com. Supply domain or domains, never both."},"domains":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500,"description":"Bare domains to unblock. Supply domains or domain, never both."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_suppressed_domains_remove"]}},"/api/cli/suppressions/hubspot-sync":{"get":{"operationId":"getSuppressionsHubspotSync","tags":["Suppressions"],"summary":"List HubSpot DNC Sources","description":"Lists HubSpot contact/company saved lists and readable property schemas for DNC mapping. Reads definitions only: no memberships, writes, enrollment, or outbound action. 0 credits.\n\nMCP: `oxygen_suppressions_hubspot_lists`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"query","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_suppressions_hubspot_lists"]},"post":{"operationId":"postSuppressionsHubspotSync","tags":["Suppressions"],"summary":"Configure HubSpot DNC Sync","description":"Preview or arm a bounded, additive HubSpot contact/company list → shared Oxygen DNC Workflow. Live requires approval and the exact dry-run fingerprint. Never enrolls or sends.\n\nMCP: `oxygen_suppressions_hubspot_sync`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"company_domain_property":{"type":"string","description":"Defaults to domain."},"company_linkedin_property":{"type":"string"},"company_list_id":{"type":"string"},"contact_linkedin_property":{"type":"string"},"contact_list_id":{"type":"string"},"cron":{"type":"string"},"idempotency_key":{"type":"string"},"live":{},"max_credits":{"type":"number","exclusiveMinimum":0},"max_records_per_list":{"type":"integer","minimum":1,"maximum":5000},"mode":{"type":"string","enum":["dry_run","live"]},"reviewed_fingerprint":{"type":"string"},"timezone":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_suppressions_hubspot_sync"]}},"/api/cli/suppressions/import":{"post":{"operationId":"postSuppressionsImport","tags":["Suppressions"],"summary":"Import DNC","description":"Import bundled `people`, typed `identities`, or legacy `entries`. Company domains are explicit, never inferred, and permanently block all channels and campaigns; to pause and later resume a company use oxygen_sequences_company_pause. 0 credits.\n\nMCP: `oxygen_suppressions_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string","description":"Note."},"entries":{"type":"array","items":{"type":"string"},"description":"Legacy email/domain/LinkedIn values."},"identities":{"type":"array","maxItems":5000,"items":{"type":"object","properties":{"kind":{"type":"string","enum":["email","phone","linkedin_person","company_domain","linkedin_company"]},"value":{"type":"string"},"reason":{"type":"string"},"source":{"type":"string"},"detail":{"type":"string"},"metadata":{"type":"object","additionalProperties":true}},"required":["kind","value"]},"description":"Typed identities for integrations."},"metadata":{"type":"object","additionalProperties":true,"description":"Default metadata stored on imported identities."},"people":{"type":"array","maxItems":5000,"items":{"type":"object","description":"Needs an identifier.","properties":{"subject_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"linkedin_url":{"type":"string"},"phone":{"type":"string"},"company_domain":{"type":"string","description":"Explicit; never inferred."},"reason":{"type":"string"},"source":{"type":"string"},"detail":{"type":"string"},"metadata":{"type":"object","additionalProperties":true}}},"description":"Bundled people."},"reason":{"type":"string","description":"`manual` works for all; otherwise use a valid per-type reason."},"source":{"type":"string","description":"Provenance."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_suppressions_import"]}},"/api/cli/suppressions/phones":{"get":{"operationId":"getSuppressionsPhones","tags":["Suppressions"],"summary":"List Suppressed Phone Numbers","description":"Lists strict E.164 phone suppressions used by call, WhatsApp, and Sequence safety gates. 0 credits.\n\nMCP: `oxygen_suppressions_phones_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"reason","in":"query","required":false,"schema":{"type":"string","enum":["do_not_call","wrong_number","complaint","manual"]}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_suppressions_phones_list"]},"delete":{"operationId":"deleteSuppressionsPhones","tags":["Suppressions"],"summary":"Remove Phone Suppression","description":"Deliberately re-enables one strict E.164 phone identity. List removal is never automatic. 0 credits.\n\nMCP: `oxygen_suppressions_phone_remove`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"phone","in":"query","required":false,"schema":{"type":"string","description":"One strict E.164 number."}},{"name":"phones","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_suppressions_phone_remove"]}},"/api/cli/suppressions/policy":{"get":{"operationId":"getSuppressionsPolicy","tags":["Suppressions"],"summary":"Get Do-Not-Contact Rules","description":"Rules for who is auto-added to do-not-contact: email hard bounce, one-click unsubscribe, spam complaint, opt-out wording in a reply, ANY inbound LinkedIn or WhatsApp reply, do-not-call/wrong-number outcomes, and optional per-reply-classification rules. Each is off, stop_only (not calls) or suppress. Entry only; blocking is never configurable. 0 credits.\n\nMCP: `oxygen_suppressions_policy_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_suppressions_policy_get"]},"post":{"operationId":"postSuppressionsPolicy","tags":["Suppressions"],"summary":"Set a Do-Not-Contact Rule","description":"Sets one do-not-contact rule, or resets it (reset) or all (reset_all) to the default. effect: off, stop_only (end this enrollment only), suppress (also add to the list). Rule keys from oxygen_suppressions_policy_get. 0 credits.\n\nMCP: `oxygen_suppressions_policy_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"effect":{"type":"string","enum":["off","stop_only","suppress"]},"reason":{"type":"string"},"reset":{"type":"boolean"},"resetAll":{},"reset_all":{"type":"boolean"},"rule":{"type":"string"},"ruleKey":{},"rule_key":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_suppressions_policy_set"]}},"/api/cli/table-action-items/{itemId}/resolve":{"post":{"operationId":"table_action_items.resolve","tags":["Table action items"],"summary":"Table actions resolve","description":"Record a human-verified uncertain Table action outcome without repeating it. Use cells resolve for row/column coordinates.\n\nCLI: `oxygen table-actions resolve`.\n\nMCP: `oxygen_table_action_item_resolve`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"itemId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["applied","not_applied"]},"note":{"type":"string"},"value":{"description":"Verified cell result; any JSON, including null."}},"required":["outcome"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_action_item_resolve"],"x-oxygen-cli-command":"oxygen table-actions resolve"}},"/api/cli/table-action-runs":{"get":{"operationId":"table_action_runs.list","tags":["Table action runs"],"summary":"Table runs list","description":"Read durable Table action runs, optionally filtered by status or trace.\n\nMCP: `oxygen_table_action_runs_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"trace_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_action_runs_list"]},"post":{"operationId":"postTableActionRuns","tags":["Table action runs"],"summary":"Start Table Action Run","description":"Creates a background table action run over selected rows (tool/AI/enrichment columns). Paid: approved=true + max_credits after a dry run. Large runs: execution_status=planning.\n\nMCP: `oxygen_table_runs_create`, `oxygen_tools_plan_table_batch`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"actions":{"type":"array","description":"Action descriptors, e.g. [{type:'tool_column', column:'company_domain'}]. Plan max 10-50 (oxygen_limits_show); tool/AI/formula/enrichment runnable.","items":{"type":"object","additionalProperties":true},"minItems":1,"maxItems":50},"approved":{"type":"boolean","description":"approved=true to run paid table action runs after a dry run or preview."},"connectionId":{},"connection_id":{"type":"string"},"force":{"type":"boolean","description":"Re-run rows even if cells are populated."},"idempotencyKey":{},"idempotency_key":{"type":"string","maxLength":200},"max_concurrency":{"type":"integer","description":"Maximum concurrent row items for this run.","minimum":1,"maximum":4000},"max_credits":{"type":"number","description":"Max credits reserved as a ceiling for paid runs. Unused credits are not spent.","exclusiveMinimum":0},"metadata":{},"selection":{"type":"object","description":"Select all, limit, row_ids, or filter rows.","properties":{"mode":{"type":"string","enum":["all","limit","row_ids","filter"]},"limit":{"type":"integer","minimum":1,"maximum":1000000},"row_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":1000000},"filters":{"type":"array","items":{"type":"object","description":"Simple server-side row filter.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","contains","not_contains","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"minItems":1,"maxItems":20},"formula_values":{"type":"string","enum":["materialized"],"description":"Default is refused. Force-rerun the selector formula first (0 credits), then use this stored-snapshot mode."}},"required":["mode"]},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{},"then":{"type":"array","description":"Follow-up run steps; each paid step needs its own selection and max_credits.","items":{"type":"object","description":"Follow-up run step; paid steps need their own selection and max_credits.","properties":{"actions":{"type":"array","description":"Action descriptors, e.g. [{type:'tool_column', column:'company_domain'}]. Plan max 10-50 (oxygen_limits_show); tool/AI/formula/enrichment runnable.","items":{"type":"object","additionalProperties":true},"minItems":1,"maxItems":50},"selection":{"type":"object","description":"Select all, limit, row_ids, or filter rows.","properties":{"mode":{"type":"string","enum":["all","limit","row_ids","filter"]},"limit":{"type":"integer","minimum":1,"maximum":1000000},"row_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":1000000},"filters":{"type":"array","items":{"type":"object","description":"Simple server-side row filter.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","contains","not_contains","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"minItems":1,"maxItems":20},"formula_values":{"type":"string","enum":["materialized"],"description":"Default is refused. Force-rerun the selector formula first (0 credits), then use this stored-snapshot mode."}},"required":["mode"]},"force":{"type":"boolean","description":"Re-run rows even if cells are populated."},"max_credits":{"type":"number","description":"Credit ceiling for this chain step.","exclusiveMinimum":0},"max_concurrency":{"type":"integer","description":"Max concurrent row items for this chain step.","minimum":1,"maximum":4000},"metadata":{"type":"object","additionalProperties":true},"run_on_failure":{"type":"boolean","description":"Run this step even if the parent run failed or was canceled."},"runOnFailure":{"type":"boolean","description":"Alias for run_on_failure."}},"required":["actions"],"additionalProperties":true},"minItems":1,"maxItems":20}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_runs_create","oxygen_tools_plan_table_batch"]}},"/api/cli/table-action-runs/{actionRunId}":{"get":{"operationId":"getTableActionRunsActionRunId","tags":["Table action runs"],"summary":"Get Table Action Run","description":"Read one Table run: status, counts, costs and failures. Summary omits inputs/metadata.\n\nMCP: `oxygen_table_runs_get`, `oxygen_table_runs_wait`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["summary","full"],"description":"Default full; summary for progress."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_runs_get","oxygen_table_runs_wait"]}},"/api/cli/table-action-runs/{actionRunId}/cancel":{"post":{"operationId":"postTableActionRunsActionRunIdCancel","tags":["Table action runs"],"summary":"Cancel Table Action Run","description":"Cancels a table action run; imports use oxygen_table_ingestions_cancel.\n\nMCP: `oxygen_table_runs_cancel`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_runs_cancel"]}},"/api/cli/table-action-runs/{actionRunId}/effect-unknown":{"get":{"operationId":"getTableActionRunsActionRunIdEffectUnknown","tags":["Table action runs"],"summary":"List Effect-Unknown Items","description":"Lists the items of a table action run whose external write (a custom HTTP POST) was dispatched but never confirmed — codes custom_http_effect_unknown / worker_step_outcome_unknown. Oxygen cannot tell whether the write landed, so these items are blocked from automatic retry until a human verifies the destination and records the outcome with oxygen_table_action_item_resolve by item_id or oxygen_table_cells_resolve by cell coordinates. Read-only, free, no provider call.\n\nMCP: `oxygen_table_runs_effect_unknown`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}},{"name":"include_resolved","in":"query","required":false,"schema":{"type":"boolean","description":"true also returns items a human has already verified. Defaults to false (only what still awaits a verdict)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_runs_effect_unknown"]}},"/api/cli/table-action-runs/{actionRunId}/items":{"get":{"operationId":"getTableActionRunsActionRunIdItems","tags":["Table action runs"],"summary":"List Table Action Run Items","description":"Lists per-row items for a table action run, optionally filtered by status. Use to inspect failures.\n\nMCP: `oxygen_table_runs_items`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Optional status filter.","enum":["pending","leased","completed","failed","skipped","canceled"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_runs_items"]}},"/api/cli/table-action-runs/{actionRunId}/pause":{"post":{"operationId":"postTableActionRunsActionRunIdPause","tags":["Table action runs"],"summary":"Pause Table Action Run","description":"Pauses a run so item jobs start no new provider calls until resumed.\n\nMCP: `oxygen_table_runs_pause`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_runs_pause"]}},"/api/cli/table-action-runs/{actionRunId}/provider-summary":{"get":{"operationId":"getTableActionRunsActionRunIdProviderSummary","tags":["Table action runs"],"summary":"Table Run Provider Summary","description":"Summarizes provider attempts, no-results, errors, upstream request events, poll statuses, and credit capture/release for a table action run.\n\nMCP: `oxygen_table_runs_provider_summary`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_runs_provider_summary"]}},"/api/cli/table-action-runs/{actionRunId}/resume":{"post":{"operationId":"postTableActionRunsActionRunIdResume","tags":["Table action runs"],"summary":"Resume Table Action Run","description":"Resumes a paused table action run and re-enqueues pending item jobs.\n\nMCP: `oxygen_table_runs_resume`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_runs_resume"]}},"/api/cli/table-action-runs/{actionRunId}/retry-failed":{"get":{"operationId":"getTableActionRunsActionRunIdRetryFailed","tags":["Table action runs"],"summary":"Preview Run Retry","description":"Read failed/dependent items or pending guarded callbacks, billing, refusals and approval hash. No writes or calls. Quote paid retries; callbacks-only delivery requires 0 additional credits.\n\nMCP: `oxygen_table_runs_retry_plan`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_runs_retry_plan"]},"post":{"operationId":"postTableActionRunsActionRunIdRetryFailed","tags":["Table action runs"],"summary":"Retry Failed Items","description":"Retry failed items or wake guarded callbacks from saved results. Inspect retry_plan; pass approved, retry_plan_hash and max_additional_credits (0 for callbacks only). Paid retries need a fresh quote; unconfirmed effects stay blocked.\n\nMCP: `oxygen_table_runs_retry_failed`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"approved_effect_unknown":{"type":"boolean","description":"Set true only after a human verifies every effect_unknown item listed by the refusal and confirms another external execution is safe."},"max_additional_credits":{"type":"number","minimum":0},"retry_plan_hash":{"type":"string","minLength":64,"maxLength":64}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_runs_retry_failed"]}},"/api/cli/table-action-runs/{actionRunId}/run-now":{"post":{"operationId":"postTableActionRunsActionRunIdRunNow","tags":["Table action runs"],"summary":"Run Deadline-Queued Run Now","description":"Starts a deadline-queued scheduled run now (pacing.state=queued) instead of when the deadline queue would. No-op once started.\n\nMCP: `oxygen_table_runs_run_now`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"actionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_runs_run_now"]}},"/api/cli/table-ingestion-runs":{"post":{"operationId":"postTableIngestionRuns","tags":["Table ingestion runs"],"summary":"Create Table Ingestion","description":"Creates a durable Table ingestion for row chunks or bounded provider pages (source_type=tool_page; items contain the paging payload). For CSV/Excel/JSON files, use oxygen_tables_import_upload, import_preview and import_staged; default source_type is mcp.rows_inline.\n\nMCP: `oxygen_table_ingestions_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{},"connection_id":{"type":"string","description":"Workspace source connection persisted with this ingestion."},"expected_item_count":{"type":"integer","description":"Expected number of chunks/items to append.","minimum":0},"items":{"type":"array","description":"Initial items: {position,payload:{rows:[...]}}. For source_type=tool_page, payload is {tool_id,request,rows_path,row_mapping,cursor_path,cursor_request_key,max_pages}; row_mapping maps Table column keys to paths within each source row. LinkedIn ads: tool_id=adyntel.linkedin_ads, request={company_domain:example.com}, rows_path=response.ads, row_mapping={ad_id:ad_id,advertiser:advertiser.name}, cursor_path=response.continuation_token, cursor_request_key=continuation_token. max_pages is per initial item/cursor chain, a positive integer defaulting to 1; set max_credits and upsert with an ad-ID column. Completed is bounded work, not all pages: inspect oxygen_table_ingestions_items for output.has_next_cursor, output.stopped_by and nextCursor. For owned files use oxygen_tables_import_staged.","items":{"type":"object","description":"Ingestion item, usually {position, payload:{rows:[...]}}.","additionalProperties":true},"minItems":1,"maxItems":100},"max_attempts":{"type":"integer","description":"Maximum attempts per item.","minimum":1,"maximum":10},"max_concurrency":{"type":"integer","description":"Maximum concurrent ingestion items.","minimum":1,"maximum":1000},"max_credits":{"type":"number","description":"Credit cap; required for paid tool_page items.","exclusiveMinimum":0},"metadata":{"type":"object","description":"Optional metadata to attach to the ingestion run.","additionalProperties":true},"mode":{"type":"string","description":"insert appends rows; upsert deduplicates using upsert_key.","enum":["insert","upsert"]},"source_type":{"type":"string","description":"tool_page fetches bounded provider pages using items[].payload; mcp.rows_inline writes supplied rows.","minLength":1,"maxLength":120},"table":{"type":"string","description":"Table id or slug.","minLength":1,"maxLength":200},"upsertKey":{},"upsert_key":{"type":"string","description":"Column key required when mode is upsert.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_ingestions_create"]}},"/api/cli/table-ingestion-runs/{ingestionRunId}":{"get":{"operationId":"getTableIngestionRunsIngestionRunId","tags":["Table ingestion runs"],"summary":"Get Table Ingestion","description":"Returns ingestion status/counts and its web link. For tool_page, completed means bounded work finished; inspect oxygen_table_ingestions_items for output.has_next_cursor, output.stopped_by and nextCursor to distinguish more pages from cursor exhaustion.\n\nMCP: `oxygen_table_ingestions_get`, `oxygen_table_ingestions_wait`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"ingestionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_ingestions_get","oxygen_table_ingestions_wait"]}},"/api/cli/table-ingestion-runs/{ingestionRunId}/cancel":{"post":{"operationId":"postTableIngestionRunsIngestionRunIdCancel","tags":["Table ingestion runs"],"summary":"Cancel Table Ingestion","description":"Requests cancellation for a queued or running durable table ingestion.\n\nMCP: `oxygen_table_ingestions_cancel`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"ingestionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_ingestions_cancel"]}},"/api/cli/table-ingestion-runs/{ingestionRunId}/items":{"get":{"operationId":"getTableIngestionRunsIngestionRunIdItems","tags":["Table ingestion runs"],"summary":"List Ingestion Items","description":"Lists ingestion items, including completed pages. tool_page item.output.has_next_cursor=true means more pages remain; item.output.stopped_by=provider_exhausted records cursor exhaustion. Saved item.nextCursor continues via a new approved oxygen_table_ingestions_create run in the same Table with the same filters/mapping/ad-ID upsert and a new cap. Inspect failed/unknown outcomes before retrying. Adyntel guide: oxygen_skills_get oxygen-signals, file provider-runbooks/adyntel.md.\n\nMCP: `oxygen_table_ingestions_items`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"ingestionRunId","in":"path","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Optional item status filter.","enum":["pending","leased","completed","failed","skipped","canceled"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_ingestions_items"]},"post":{"operationId":"table_ingestions.append","tags":["Table ingestion runs"],"summary":"Append Ingestion Items","description":"Append generated row chunks with items [{position:0,payload:{rows:[{column:value}]}}]. For capped provider paging, create a new approved tool_page run from the last completed item.nextCursor; preserve the Table, filters/mapping/upsert key and use a new credit cap.\n\nCLI: `oxygen table-ingestions append`.\n\nMCP: `oxygen_table_ingestions_append_items`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"ingestionRunId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"max_attempts":{"type":"integer","minimum":1}},"required":["items"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_ingestions_append_items"],"x-oxygen-cli-command":"oxygen table-ingestions append"}},"/api/cli/table-ingestion-runs/{ingestionRunId}/retry-failed":{"post":{"operationId":"postTableIngestionRunsIngestionRunIdRetryFailed","tags":["Table ingestion runs"],"summary":"Retry Failed Ingestion Items","description":"Requeues failed items for a durable table ingestion after you have inspected and fixed the cause.\n\nMCP: `oxygen_table_ingestions_retry_failed`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"ingestionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_ingestions_retry_failed"]}},"/api/cli/tables":{"get":{"operationId":"getTables","tags":["Tables"],"summary":"List Tables","description":"Lists 50 summary tables. Resume nextCursor with unchanged filters. null rowCount is unknown; measure with oxygen_tables_describe include_stats:true. Largest: oxygen_limits_show.\n\nMCP: `oxygen_tables_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"project","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"tag","in":"query","required":false,"schema":{"type":"string"}},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"x-clamp":true}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","maxLength":2000}},{"name":"query","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Name/slug substring."}},{"name":"projection","in":"query","required":false,"schema":{"type":"string","enum":["full","summary"]}},{"name":"max_chars","in":"query","required":false,"schema":{"type":"integer","minimum":2000,"maximum":40000}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_list"]},"post":{"operationId":"postTables","tags":["Tables"],"summary":"Create Table","description":"Creates a table private to the active workspace. Mutates tenant schema. AI prompts read {{column_key}} or inputMapping {{name}}; unknown → invalid_prompt_column + near misses.\n\nMCP: `oxygen_tables_create`, `oxygen_tools_plan_table_batch`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"columns":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":200},"key":{"type":"string","description":"snake_case.","maxLength":64},"data_type":{"type":"string","description":"Default text.","enum":["text","numeric","boolean","jsonb","timestamptz","number","json","date","url","email"]},"kind":{"type":"string","description":"Default manual; research=Web Research Agent, ai=row prompts. bind=CRM records; lookup=other Table; oxygen_tables_relate links two.","enum":["manual","source","ai","research","tool","formula","enrichment","bind","lookup"]},"semantic_type":{"type":"string","maxLength":80},"type":{"type":"string","description":"Field type; choice types take definition.options.","enum":["text","number","checkbox","date","json","markdown","image","select","multi_select","status"]},"definition":{"type":"object","description":"toolId accepts tools-search ids, including composio.*.","properties":{"mode":{"type":"string","enum":["native","first_match","count","exists","aggregate"]},"toolId":{"type":"string"},"credentialMode":{"type":"string","enum":["managed","user_api_key","user_oauth"]},"inputMapping":{"type":"object","description":"Inputs.","additionalProperties":{"oneOf":[{"type":"string","description":"Column key"},{"type":"object","properties":{"type":{"type":"string","enum":["column","literal","template"],"description":"columnKey; nested refs; {{key}} template."},"columnKey":{"type":"string"},"column_key":{"type":"string"}},"additionalProperties":true}]}},"prompt":{"type":"string","description":"{{column_key}}."},"model":{"type":"string","description":"Managed allowlist; BYOK any."},"reasoningLevel":{"type":"string","enum":["low","medium","high"]},"runCondition":{"type":"object","description":"Truthy.","properties":{"type":{"type":"string","enum":["formula"]},"expression":{"type":"string"},"referencedColumns":{"type":"array","description":"Expression's snake_case keys.","items":{"type":"string"}}},"required":["type","expression"],"additionalProperties":true},"options":{"type":"array","description":"Choice-column options; cells store value.","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"color":{"type":"string","enum":["gray","red","orange","amber","yellow","green","teal","blue","indigo","purple","pink"]},"order":{"type":"integer"}},"required":["value"],"additionalProperties":true}}},"additionalProperties":true}},"required":["label"]},"minItems":1,"maxItems":100},"name":{"type":"string","description":"Table display name.","minLength":1,"maxLength":200},"project":{"type":"string","description":"ID or slug; default General.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_create","oxygen_tools_plan_table_batch"]}},"/api/cli/tables/{tableIdOrSlug}":{"patch":{"operationId":"tables.resource.edit","tags":["Tables"],"summary":"Tables edit","description":"Rename a Table or move it to a workspace project; returns the saved Table.\n\nCLI: `oxygen tables edit`.\n\nMCP: `oxygen_table_resource_edit`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"project_id":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_resource_edit"],"x-oxygen-cli-command":"oxygen tables edit"},"delete":{"operationId":"tables.resource.archive","tags":["Tables"],"summary":"Archive Table","description":"Archive a Table indefinitely without dropping its physical data or scheduling a purge.\n\nMCP: `oxygen_tables_archive`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_archive"]}},"/api/cli/tables/{tableIdOrSlug}/action-columns":{"post":{"operationId":"tables.resource.action_columns","tags":["Tables"],"summary":"Columns provider action","description":"Preview or create a provider action column; creating it does not execute provider actions.\n\nCLI: `oxygen columns provider-action`.\n\nMCP: `oxygen_table_provider_action_column`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string"},"label":{"type":"string"},"key":{"type":"string"},"operations":{"type":"array","items":{"type":"string"}},"dry_run":{"type":"boolean"}},"required":["provider"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_provider_action_column"],"x-oxygen-cli-command":"oxygen columns provider-action"}},"/api/cli/tables/{tableIdOrSlug}/activity":{"get":{"operationId":"tables.resource.activity","tags":["Tables"],"summary":"Tables changes","description":"Read a Table's live runs and queue health.\n\nCLI: `oxygen tables changes`.\n\nMCP: `oxygen_table_resource_activity`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_resource_activity"],"x-oxygen-cli-command":"oxygen tables changes"}},"/api/cli/tables/{tableIdOrSlug}/column-stats":{"get":{"operationId":"tables.resource.column_stats","tags":["Tables"],"summary":"Tables column stats","description":"Read per-column completion and provider statistics; large Tables use labeled samples.\n\nCLI: `oxygen tables column-stats`.\n\nMCP: `oxygen_table_column_stats`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_column_stats"],"x-oxygen-cli-command":"oxygen tables column-stats"}},"/api/cli/tables/{tableIdOrSlug}/columns":{"post":{"operationId":"tables.resource.columns.create","tags":["Tables"],"summary":"Columns create","description":"Create a Table column at an optional zero-based position; type is a field type, and a choice type takes options (cells store each value).\n\nCLI: `oxygen columns create`.\n\nMCP: `oxygen_table_column_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"object","additionalProperties":false,"properties":{"label":{"type":"string"},"key":{"type":"string"},"kind":{"type":"string"},"type":{"type":"string","enum":["text","number","checkbox","date","json","markdown","image","select","multi_select","status"]},"options":{"type":"array","items":{}},"data_type":{"type":"string","enum":["text","numeric","boolean","jsonb","timestamptz"]},"semantic_type":{"type":"string"},"definition":{"type":"object","additionalProperties":true}},"required":["label"]},"position":{"type":"integer","minimum":0}},"required":["column"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_column_create"],"x-oxygen-cli-command":"oxygen columns create"}},"/api/cli/tables/{tableIdOrSlug}/columns/{columnIdOrKey}":{"patch":{"operationId":"tables.resource.columns.edit","tags":["Tables"],"summary":"Columns edit","description":"Save a column's label, type, order or definition. Returns downstream reference warnings rather than silently discarding them.\n\nCLI: `oxygen columns edit`.\n\nMCP: `oxygen_table_column_edit`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"columnIdOrKey","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string"},"semantic_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"definition":{"type":"object","additionalProperties":true},"definition_unset":{"type":"array","items":{"type":"string"}},"data_type":{"type":"string","enum":["text","numeric","boolean","jsonb","timestamptz"]},"position":{"type":"integer","minimum":0}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_column_edit"],"x-oxygen-cli-command":"oxygen columns edit"}},"/api/cli/tables/{tableIdOrSlug}/columns/{columnIdOrKey}/archive":{"post":{"operationId":"tables.resource.columns.archive","tags":["Tables"],"summary":"Archive Column","description":"Archive a Table column indefinitely while preserving its stored values.\n\nMCP: `oxygen_columns_archive`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"columnIdOrKey","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_archive"]}},"/api/cli/tables/{tableIdOrSlug}/columns/{columnIdOrKey}/duplicate":{"post":{"operationId":"tables.resource.columns.duplicate","tags":["Tables"],"summary":"Columns duplicate","description":"Duplicate a Table column and its definition with an optional new label.\n\nCLI: `oxygen columns duplicate`.\n\nMCP: `oxygen_table_column_duplicate`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"columnIdOrKey","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_column_duplicate"],"x-oxygen-cli-command":"oxygen columns duplicate"}},"/api/cli/tables/{tableIdOrSlug}/columns/{columnIdOrKey}/materialize":{"post":{"operationId":"tables.resource.columns.materialize","tags":["Tables"],"summary":"Materialize Column Results","description":"Materialize JSON paths into existing or newly created companion columns.\n\nMCP: `oxygen_columns_materialize`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"columnIdOrKey","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"preset":{"type":"string","enum":["work_email"]},"mappings":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"source_path":{"type":"string"},"target_column":{"type":"string"},"label":{"type":"string"},"data_type":{"type":"string","enum":["text","numeric","boolean","jsonb","timestamptz"]},"semantic_type":{"type":"string"}},"required":["source_path","target_column"]}},"create_if_missing":{"type":"boolean"},"overwrite_existing":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_materialize"]}},"/api/cli/tables/{tableIdOrSlug}/columns/{columnIdOrKey}/retype":{"post":{"operationId":"tables.resource.columns.retype","tags":["Tables"],"summary":"Retype Column","description":"Preview or apply a manual column's stored-value type conversion.\n\nMCP: `oxygen_columns_retype`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"columnIdOrKey","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"data_type":{"type":"string","enum":["text","numeric","boolean","jsonb","timestamptz"]},"dry_run":{"type":"boolean"}},"required":["data_type"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_retype"]}},"/api/cli/tables/{tableIdOrSlug}/columns/{columnIdOrKey}/run":{"post":{"operationId":"tables.resource.columns.run","tags":["Tables"],"summary":"Columns execute","description":"Run one column over an exact row or bounded selection. Paid execution requires approval and a max_credits ceiling; uncertain prior effects need explicit resolution approval.\n\nCLI: `oxygen columns execute`.\n\nMCP: `oxygen_table_column_execute`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"columnIdOrKey","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"row_id":{"type":"string"},"force":{"type":"boolean"},"limit":{"type":"integer","minimum":1},"full_table_mode":{"type":"string","enum":["missing","force"]},"max_credits":{"type":"number","minimum":0},"max_concurrency":{"type":"integer","minimum":1},"connection_id":{"type":"string"},"approved":{"type":"boolean"},"approved_effect_unknown":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_table_column_execute"],"x-oxygen-cli-command":"oxygen columns execute"}},"/api/cli/tables/{tableIdOrSlug}/columns/{columnIdOrKey}/web-search-mode":{"post":{"operationId":"tables.resource.columns.web_search_mode","tags":["Tables"],"summary":"Columns web search mode","description":"Convert a web-search column between agent, AI or keyword modes. Conversion requires confirm=true; mode plus column seeds an AI or keyword replacement.\n\nCLI: `oxygen columns web-search-mode`.\n\nMCP: `oxygen_table_column_web_search_mode`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"columnIdOrKey","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","enum":["agent","ai","keyword"]},"confirm":{"type":"boolean"},"mode":{"type":"string","enum":["ai","keyword"]},"column":{"type":"object","additionalProperties":true},"prompt":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_column_web_search_mode"],"x-oxygen-cli-command":"oxygen columns web-search-mode"}},"/api/cli/tables/{tableIdOrSlug}/duplicate":{"post":{"operationId":"tables.resource.duplicate","tags":["Tables"],"summary":"Duplicate Table","description":"Duplicate a Table with its columns and optionally its row values.\n\nMCP: `oxygen_tables_duplicate`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"include_rows":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_duplicate"]}},"/api/cli/tables/{tableIdOrSlug}/export/csv":{"get":{"operationId":"tables.resource.export_csv","tags":["Tables"],"summary":"Tables export csv","description":"Download every row in the exact filtered Table view as streamed CSV. CLI writes --output; MCP returns an authenticated download resource link. Unsupported live lookup filters fail before download; rows and bytes are not capped or truncated.\n\nCLI: `oxygen tables export-csv`.\n\nMCP: `oxygen_table_export_csv`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"f","in":"query","required":false,"schema":{"type":"string","description":"Serialized filter tree."}},{"name":"s","in":"query","required":false,"schema":{"type":"string","description":"Serialized sort state."}},{"name":"q","in":"query","required":false,"schema":{"type":"string"}},{"name":"fields","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated exact column keys."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_export_csv"],"x-oxygen-cli-command":"oxygen tables export-csv"}},"/api/cli/tables/{tableIdOrSlug}/fill-progress":{"get":{"operationId":"tables.resource.fill_progress","tags":["Tables"],"summary":"Tables fill progress","description":"Read hosted Table fill progress and any actionable ingestion failure.\n\nCLI: `oxygen tables fill-progress`.\n\nMCP: `oxygen_table_fill_progress`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_fill_progress"],"x-oxygen-cli-command":"oxygen tables fill-progress"}},"/api/cli/tables/{tableIdOrSlug}/ingestions/{ingestionRunId}/cancel":{"post":{"operationId":"tables.resource.ingestions.cancel","tags":["Tables"],"summary":"Tables ingestion stop","description":"Cancel this Table's active hosted ingestion run.\n\nCLI: `oxygen tables ingestion stop`.\n\nMCP: `oxygen_table_resource_ingestion_stop`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"ingestionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_resource_ingestion_stop"],"x-oxygen-cli-command":"oxygen tables ingestion stop"}},"/api/cli/tables/{tableIdOrSlug}/ingestions/{ingestionRunId}/retry-failed":{"post":{"operationId":"tables.resource.ingestions.retry","tags":["Tables"],"summary":"Tables ingestion retry","description":"Retry failed items in this Table's hosted ingestion run.\n\nCLI: `oxygen tables ingestion retry`.\n\nMCP: `oxygen_table_resource_ingestion_retry`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"ingestionRunId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_resource_ingestion_retry"],"x-oxygen-cli-command":"oxygen tables ingestion retry"}},"/api/cli/tables/{tableIdOrSlug}/records/{rowId}/relationships":{"get":{"operationId":"tables.resource.relationships.get","tags":["Tables"],"summary":"Tables rows relationships","description":"Read one Table row's linked records, across Table relations and CRM relationships, and the relations it can link through.\n\nCLI: `oxygen tables rows relationships`.\n\nMCP: `oxygen_table_row_relationships`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_row_relationships"],"x-oxygen-cli-command":"oxygen tables rows relationships"},"post":{"operationId":"tables.resource.relationships.set","tags":["Tables"],"summary":"Tables rows relationship set","description":"Link one Table row to a target row through a relation (Table or CRM) and return the link.\n\nCLI: `oxygen tables rows relationship-set`.\n\nMCP: `oxygen_table_row_relationship_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"relationship":{"type":"string","description":"Relation slug: the linked-record column key."},"target_row_id":{"type":"string","description":"Row id in the related table."}},"required":["relationship","target_row_id"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_row_relationship_set"],"x-oxygen-cli-command":"oxygen tables rows relationship-set"}},"/api/cli/tables/{tableIdOrSlug}/rows":{"get":{"operationId":"tables.resource.rows.page","tags":["Tables"],"summary":"Tables rows page","description":"Read a Table row page with the same filter, sort, counts and CRM relationship projection as the grid.\n\nCLI: `oxygen tables rows page`.\n\nMCP: `oxygen_table_rows_page`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"f","in":"query","required":false,"schema":{"type":"string","description":"Serialized filter tree."}},{"name":"s","in":"query","required":false,"schema":{"type":"string","description":"Serialized sort state."}},{"name":"q","in":"query","required":false,"schema":{"type":"string"}},{"name":"count","in":"query","required":false,"schema":{"type":"string","enum":["exact","estimate","registry","skip"]}},{"name":"crm_object","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_rows_page"],"x-oxygen-cli-command":"oxygen tables rows page"},"post":{"operationId":"tables.resource.rows.insert","tags":["Tables"],"summary":"Tables rows insert","description":"Insert Table row values and return the committed rows plus any existing automatic run or dedupe grant.\n\nCLI: `oxygen tables rows insert`.\n\nMCP: `oxygen_table_rows_insert`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","additionalProperties":true}},"values":{"type":"object","additionalProperties":true}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_rows_insert"],"x-oxygen-cli-command":"oxygen tables rows insert"}},"/api/cli/tables/{tableIdOrSlug}/rows/{rowId}":{"get":{"operationId":"tables.resource.rows.get","tags":["Tables"],"summary":"Tables rows inspect","description":"Read one row; field selects column keys and hydrate_relations=1 includes relations. projection=value returns lossless JSON fragments; resume value_cursor with identical table/row/field/path.\n\nCLI: `oxygen tables rows inspect`.\n\nMCP: `oxygen_table_row_inspect`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}},{"name":"hydrate_relations","in":"query","required":false,"schema":{"type":"string","enum":["1"]}},{"name":"field","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"}}},{"name":"projection","in":"query","required":false,"schema":{"type":"string","enum":["full","value"],"description":"value: lossless JSON fragments; full: complete result. Omit for legacy."}},{"name":"path","in":"query","required":false,"schema":{"type":"string","maxLength":1024,"description":"JSON Pointer; empty=root."}},{"name":"value_cursor","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":2000,"description":"Resume with identical selection/path."}},{"name":"max_chars","in":"query","required":false,"schema":{"type":"integer","minimum":1000,"maximum":40000,"description":"Receipt cap; MCP 10000, built-in 4000."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_row_inspect"],"x-oxygen-cli-command":"oxygen tables rows inspect"},"patch":{"operationId":"tables.resource.rows.edit","tags":["Tables"],"summary":"Tables rows edit","description":"Patch one row's values and return the committed row.\n\nCLI: `oxygen tables rows edit`.\n\nMCP: `oxygen_table_row_edit`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"values":{"type":"object","additionalProperties":true}},"required":["values"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_row_edit"],"x-oxygen-cli-command":"oxygen tables rows edit"},"delete":{"operationId":"tables.resource.rows.delete","tags":["Tables"],"summary":"Tables rows remove","description":"Remove one row from a workspace Table.\n\nCLI: `oxygen tables rows remove`.\n\nMCP: `oxygen_table_row_remove`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"rowId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_row_remove"],"x-oxygen-cli-command":"oxygen tables rows remove"}},"/api/cli/tables/{tableIdOrSlug}/rows/delete":{"post":{"operationId":"tables.resource.rows.bulk_delete","tags":["Tables"],"summary":"Tables rows remove selection","description":"Permanently delete Table rows by a readable filter tree, exact ids or a matching selection. Unsupported scope fields are refused.\n\nCLI: `oxygen tables rows remove-selection`.\n\nMCP: `oxygen_table_rows_remove_selection`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"row_ids":{"type":"array","items":{"type":"string","minLength":1},"minItems":1},"filter_tree":{"description":"Remove the rows this filter tree matches (as tables query takes), e.g. {\"type\":\"group\",\"children\":[{\"type\":\"leaf\",\"columnKey\":\"status\",\"operator\":\"is\",\"value\":\"churned\"}]} (text: is/is_not/contains; numbers: eq/gt/lt). Unreadable nodes are refused. Not with row_ids/selection."},"selection":{"description":"{\"mode\":\"row_ids\",\"row_ids\":[\"id\"]} or {\"mode\":\"all_matching\",\"filter_tree\":{...}}, with optional search, sort, range {offset,limit}, excluded_row_ids, crm_object. Unreadable filter nodes and filters/limit are refused. Unqualified all_matching removes every row.","oneOf":[{"type":"object","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["row_ids"]},"row_ids":{"type":"array","items":{"type":"string","minLength":1},"minItems":1}},"required":["mode","row_ids"]},{"type":"object","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["all_matching"]},"filter_tree":{"description":"Readable filter tree, as tables query takes. Not with filter."},"filter":{"type":"string","description":"Browser URL filter (f). Not with filter_tree."},"search":{"type":"string"},"sort":{"type":"string"},"range":{"type":"object","additionalProperties":false,"properties":{"offset":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1}},"required":["offset","limit"]},"excluded_row_ids":{"type":"array","items":{"type":"string","minLength":1}},"crm_object":{"type":"string"}},"required":["mode"]}]}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_table_rows_remove_selection"],"x-oxygen-cli-command":"oxygen tables rows remove-selection"}},"/api/cli/tables/{tableIdOrSlug}/rows/ids":{"get":{"operationId":"tables.resource.rows.ids","tags":["Tables"],"summary":"Tables rows range ids","description":"Resolve a bounded row range into exact ids, preserving the current filter, search, sort and CRM scope.\n\nCLI: `oxygen tables rows range-ids`.\n\nMCP: `oxygen_table_rows_range_ids`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"offset","in":"query","required":true,"schema":{"type":"integer","minimum":0}},{"name":"limit","in":"query","required":true,"schema":{"type":"integer","minimum":1}},{"name":"filter","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string"}},{"name":"crm_object","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_rows_range_ids"],"x-oxygen-cli-command":"oxygen tables rows range-ids"}},"/api/cli/tables/{tableIdOrSlug}/runs":{"get":{"operationId":"tables.resource.runs.list","tags":["Tables"],"summary":"Tables runs history","description":"Read this Table's action-run history and progress.\n\nCLI: `oxygen tables runs history`.\n\nMCP: `oxygen_table_runs_history`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["all","active","queued","running","paused","completed","completed_with_errors","failed","canceling","canceled"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_runs_history"],"x-oxygen-cli-command":"oxygen tables runs history"},"post":{"operationId":"tables.resource.runs.start","tags":["Tables"],"summary":"Tables runs start","description":"Start selected Table actions using the browser's exact row-selection contract. Paid runs require an approved max_credits ceiling.\n\nCLI: `oxygen tables runs start`.\n\nMCP: `oxygen_table_resource_run_start`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"actions":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["tool_column"]},"column":{"type":"string"},"definition":{"type":"object","additionalProperties":true}},"required":["column"]}},"selection":{"type":"object","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["all","limit","row_ids","filter","all_matching"]},"limit":{"type":"integer","minimum":1},"row_ids":{"type":"array","items":{"type":"string"}},"filters":{"type":"array","items":{"type":"object","additionalProperties":true}},"filter":{"type":"string","description":"Serialized browser filter tree."},"search":{"type":"string"},"sort":{"type":"string"},"crm_object":{"type":"string"},"range":{"type":"object","additionalProperties":false,"properties":{"offset":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1}},"required":["offset","limit"]}},"required":["mode"]},"max_credits":{"type":"number","minimum":0},"max_concurrency":{"type":"integer","minimum":1},"force":{"type":"boolean"},"approved":{"type":"boolean"}},"required":["actions"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_table_resource_run_start"],"x-oxygen-cli-command":"oxygen tables runs start"}},"/api/cli/tables/{tableIdOrSlug}/runs/{runId}/cancel":{"post":{"operationId":"tables.resource.runs.cancel","tags":["Tables"],"summary":"Tables runs stop","description":"Cancel one durable Table run; never repeats external provider effects.\n\nCLI: `oxygen tables runs stop`.\n\nMCP: `oxygen_table_resource_run_stop`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_resource_run_stop"],"x-oxygen-cli-command":"oxygen tables runs stop"}},"/api/cli/tables/{tableIdOrSlug}/runs/{runId}/pause":{"post":{"operationId":"tables.resource.runs.pause","tags":["Tables"],"summary":"Tables runs pause","description":"Pause one durable Table run without discarding its approved scope.\n\nCLI: `oxygen tables runs pause`.\n\nMCP: `oxygen_table_resource_run_pause`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_resource_run_pause"],"x-oxygen-cli-command":"oxygen tables runs pause"}},"/api/cli/tables/{tableIdOrSlug}/runs/{runId}/provider-summary":{"get":{"operationId":"tables.resource.runs.provider_summary","tags":["Tables"],"summary":"Tables runs provider summary","description":"Read a Table run's provider outcomes, fulfilled rows, costs and timing.\n\nCLI: `oxygen tables runs provider-summary`.\n\nMCP: `oxygen_table_resource_run_provider_summary`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_resource_run_provider_summary"],"x-oxygen-cli-command":"oxygen tables runs provider-summary"}},"/api/cli/tables/{tableIdOrSlug}/runs/{runId}/resume":{"post":{"operationId":"tables.resource.runs.resume","tags":["Tables"],"summary":"Tables runs resume","description":"Resume a paused Table run within its existing approved scope and credit ceiling.\n\nCLI: `oxygen tables runs resume`.\n\nMCP: `oxygen_table_resource_run_resume`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_resource_run_resume"],"x-oxygen-cli-command":"oxygen tables runs resume"}},"/api/cli/tables/{tableIdOrSlug}/runs/{runId}/retry-failed":{"post":{"operationId":"tables.resource.runs.retry","tags":["Tables"],"summary":"Tables runs retry","description":"Retry failed cells; a fresh allowance requires approved, retry_plan_hash and max_additional_credits. Uncertain effects require separate approval.\n\nCLI: `oxygen tables runs retry`.\n\nMCP: `oxygen_table_resource_run_retry`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approved_effect_unknown":{"type":"boolean"},"approved":{"type":"boolean"},"retry_plan_hash":{"type":"string"},"max_additional_credits":{"type":"number","minimum":0}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_table_resource_run_retry"],"x-oxygen-cli-command":"oxygen tables runs retry"}},"/api/cli/tables/{tableIdOrSlug}/runs/estimate":{"post":{"operationId":"tables.resource.runs.estimate","tags":["Tables"],"summary":"Tables runs preview","description":"Preview selected Table action costs and provider availability, including draft column definitions; starts no run.\n\nCLI: `oxygen tables runs preview`.\n\nMCP: `oxygen_table_resource_run_preview`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"actions":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["tool_column"]},"column":{"type":"string"},"definition":{"type":"object","additionalProperties":true}},"required":["column"]}},"selection":{"type":"object","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["all","limit","row_ids","filter","all_matching"]},"limit":{"type":"integer","minimum":1},"row_ids":{"type":"array","items":{"type":"string"}},"filters":{"type":"array","items":{"type":"object","additionalProperties":true}},"filter":{"type":"string","description":"Serialized browser filter tree."},"search":{"type":"string"},"sort":{"type":"string"},"crm_object":{"type":"string"},"range":{"type":"object","additionalProperties":false,"properties":{"offset":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1}},"required":["offset","limit"]}},"required":["mode"]}},"required":["actions"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_resource_run_preview"],"x-oxygen-cli-command":"oxygen tables runs preview"}},"/api/cli/tables/{tableIdOrSlug}/views":{"get":{"operationId":"tables.resource.views.list","tags":["Tables"],"summary":"List Table Views","description":"List saved Table views and their complete display configuration.\n\nMCP: `oxygen_tables_views_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_views_list"]},"post":{"operationId":"tables.resource.views.create","tags":["Tables"],"summary":"Create Table View","description":"Create a saved Table view; group_by configures the same kanban grouping as the browser.\n\nMCP: `oxygen_tables_views_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"view_type":{"type":"string"},"config":{"type":"object","additionalProperties":true},"group_by":{"type":"string"},"is_default":{"type":"boolean"},"position":{"type":"integer","minimum":0}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_views_create"]}},"/api/cli/tables/{tableIdOrSlug}/views/{viewId}":{"patch":{"operationId":"tables.resource.views.edit","tags":["Tables"],"summary":"Update Table View","description":"Edit a saved view's name, type, configuration, grouping, order or default status.\n\nMCP: `oxygen_tables_views_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"viewId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"view_type":{"type":"string"},"config":{"type":"object","additionalProperties":true},"group_by":{"type":"string"},"is_default":{"type":"boolean"},"position":{"type":"integer","minimum":0}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_views_update"]},"delete":{"operationId":"tables.resource.views.delete","tags":["Tables"],"summary":"Delete Table View","description":"Delete one saved Table view.\n\nMCP: `oxygen_tables_views_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tableIdOrSlug","in":"path","required":true,"schema":{"type":"string"}},{"name":"viewId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_views_delete"]}},"/api/cli/tables/activity":{"get":{"operationId":"getTablesActivity","tags":["Tables"],"summary":"Table Background Activity","description":"Returns every active background run for a table (queued, running, or canceling) with status, item counts, throughput, ETA, credits, worker claim identity, and a worker-queue health rollup. Use to see what is running on a table right now.\n\nMCP: `oxygen_tables_activity`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Max active runs to return (1-100). Defaults to 20.","minimum":1,"maximum":100}},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"Table id or slug.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_activity"]}},"/api/cli/tables/auto-dedupe":{"get":{"operationId":"getTablesAutoDedupe","tags":["Tables"],"summary":"Table Standing Auto-Dedupe","description":"Manage a table's standing auto-dedupe: get/set/disable. When set, every write (insert/upsert/import/send/webhook) collapses duplicate groups containing a just-written row — losers are deleted into row history (kept 30 days), BEFORE any standing auto-run (survivors only). Default off. fuzzy_label is rejected; use oxygen_tables_dedupe on demand.\n\nMCP: `oxygen_tables_auto_dedupe`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_auto_dedupe"]},"post":{"operationId":"postTablesAutoDedupe","tags":["Tables"],"summary":"Table Standing Auto-Dedupe","description":"Manage a table's standing auto-dedupe: get/set/disable. When set, every write (insert/upsert/import/send/webhook) collapses duplicate groups containing a just-written row — losers are deleted into row history (kept 30 days), BEFORE any standing auto-run (survivors only). Default off. fuzzy_label is rejected; use oxygen_tables_dedupe on demand.\n\nMCP: `oxygen_tables_auto_dedupe`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"columns":{},"keep":{"type":"string","description":"set: survivor per group.","enum":["oldest","newest","most_complete"]},"keys":{"type":"array","description":"set: 1-2 key columns (composite when 2); normalizers exact/email/domain/linkedin_url.","items":{"type":"object","properties":{"column":{"type":"string","description":"Column key."},"normalizer":{"type":"string","description":"Match mode.","enum":["exact","email","domain","linkedin_url","fuzzy_label"]}},"required":["column"]},"minItems":1,"maxItems":2},"mergeValues":{},"merge_values":{"type":"string","description":"set: fill survivor blanks from losers first.","enum":["none","fill_empty"]},"normalize":{},"normalizer":{},"normalizers":{},"on":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_auto_dedupe"]},"delete":{"operationId":"deleteTablesAutoDedupe","tags":["Tables"],"summary":"Table Standing Auto-Dedupe","description":"Manage a table's standing auto-dedupe: get/set/disable. When set, every write (insert/upsert/import/send/webhook) collapses duplicate groups containing a just-written row — losers are deleted into row history (kept 30 days), BEFORE any standing auto-run (survivors only). Default off. fuzzy_label is rejected; use oxygen_tables_dedupe on demand.\n\nMCP: `oxygen_tables_auto_dedupe`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_auto_dedupe"]}},"/api/cli/tables/auto-run":{"get":{"operationId":"getTablesAutoRun","tags":["Tables"],"summary":"Table Standing Auto-Run","description":"Manage a table's standing auto-run (columns auto-queued for rows from a subscribed import/insert/upsert): get/set/disable. Default off; max_credits caps each batch.\n\nMCP: `oxygen_tables_auto_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_auto_run"]},"post":{"operationId":"postTablesAutoRun","tags":["Tables"],"summary":"Table Standing Auto-Run","description":"Manage a table's standing auto-run (columns auto-queued for rows from a subscribed import/insert/upsert): get/set/disable. Default off; max_credits caps each batch.\n\nMCP: `oxygen_tables_auto_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"columnKeys":{},"column_keys":{},"columns":{"type":"array","description":"set: column keys to auto-run (tool/ai/formula/enrichment/bind/lookup).","items":{"type":"string"},"maxItems":50},"force":{"type":"boolean","description":"set: re-run even on rows that already have values."},"maxConcurrency":{},"maxCredits":{},"max_concurrency":{"type":"integer","description":"set: max concurrent row items per batch.","minimum":1,"maximum":4000},"max_credits":{"type":"number","description":"set: credit ceiling per batch.","minimum":0},"source":{},"sources":{"type":"array","description":"set: triggering sources — import/insert/upsert/send. Default all.","items":{"type":"string","enum":["import","insert","upsert","send"]}},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_auto_run"]},"delete":{"operationId":"deleteTablesAutoRun","tags":["Tables"],"summary":"Table Standing Auto-Run","description":"Manage a table's standing auto-run (columns auto-queued for rows from a subscribed import/insert/upsert): get/set/disable. Default off; max_credits caps each batch.\n\nMCP: `oxygen_tables_auto_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_auto_run"]}},"/api/cli/tables/cells/history":{"post":{"operationId":"postTablesCellsHistory","tags":["Tables"],"summary":"Cell Change History","description":"Returns the cell-change provenance of one cell (table + row + column) — every recorded write with old → new value, the writing source (api/cli/tool/workflow/system) and run status, and timestamps. Narrower than oxygen_rows_history (one column instead of all) and lighter than oxygen_tables_cell_inspect (history only, no provider attempt timeline). Read-only.\n\nMCP: `oxygen_tables_cell_history`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string","description":"Column key or id.","minLength":1,"maxLength":200},"limit":{"type":"number","description":"Max change rows to return (default 50).","minimum":1,"maximum":200},"rowId":{},"row_id":{"type":"string","description":"Workspace row id (UUID).","minLength":1,"maxLength":64},"table":{"type":"string","description":"Workspace table id or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_cell_history"]}},"/api/cli/tables/cells/inspect":{"post":{"operationId":"postTablesCellsInspect","tags":["Tables"],"summary":"Inspect Cell","description":"Returns one cell's final value plus the full provider attempt timeline, recent write history, and a deep-link into the web app. Designed for enrichment cells (find_email / find_phone) but degrades gracefully for any column kind.\n\nMCP: `oxygen_tables_cell_inspect`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string","description":"Column key or id.","minLength":1,"maxLength":200},"historyLimit":{},"history_limit":{"type":"number","description":"Max recent cell-change rows to include (default 10, cap 50).","minimum":1,"maximum":50},"row_id":{"type":"string","description":"Workspace row id (UUID).","minLength":1,"maxLength":64},"table":{"type":"string","description":"Workspace table id or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_cell_inspect"]}},"/api/cli/tables/cells/resolve":{"post":{"operationId":"postTablesCellsResolve","tags":["Tables"],"summary":"Resolve Effect-Unknown Cell","description":"Records a HUMAN-VERIFIED outcome for a cell whose external write was dispatched but never confirmed. It NEVER re-executes the provider and never contacts the destination — it only writes down what a person actually saw there. not_applied means the write provably did not land and unblocks a normal rerun; applied means it did land and settles the cell, optionally with the value read off the destination. Never guess an outcome: list the candidates with oxygen_table_runs_effect_unknown and record only what a person verified.\n\nMCP: `oxygen_table_cells_resolve`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string","description":"ID or key.","minLength":1,"maxLength":200},"note":{"type":"string","description":"How the verification was done: what was checked, and where."},"outcome":{"type":"string","description":"applied = the external write landed. not_applied = it never did (the cell becomes rerunnable).","enum":["applied","not_applied"]},"row_id":{"type":"string","description":"Row id of the cell.","minLength":1},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":true}],"description":"The value read off the destination; only valid with outcome=applied. Omit to record no cell value."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_cells_resolve"]}},"/api/cli/tables/column-kind-estimates":{"get":{"operationId":"tables.resource.kind_estimates","tags":["Tables"],"summary":"Columns kind estimates","description":"Read managed credit estimates for available Table column kinds.\n\nCLI: `oxygen columns kind-estimates`.\n\nMCP: `oxygen_column_kind_estimates`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_column_kind_estimates"],"x-oxygen-cli-command":"oxygen columns kind-estimates"}},"/api/cli/tables/columns":{"post":{"operationId":"postTablesColumns","tags":["Tables"],"summary":"Add Column","description":"AI {{column_key}}; inputMapping literals/context; formula definition.expression (keys); research data_type=jsonb. runCondition: bare keys. preset bundles: inputs={slot:column}; company_enrich ~1 credit/profile, no field choice. prompt_key from oxygen_columns_catalog selects ai/research/search. Classify: column.definition.decision labels (labels), yes_no, score (levels ascending); prompt or decision.question. Lookup: definition.sourceTable, match{sourceColumn,normalization exact|lower_trim|email_v1|domain_v1|linkedin_url_v1}, inputMapping.match_value; first_match returnColumns, orderBy{column,direction}; aggregate={fn:sum|avg|min|max,column}. Bind: definition.object, inputMapping{identity:column}, onNoMatch none|create. Plain fields: column.type; choices in definition.options. Link tables: oxygen_tables_relate.\n\nMCP: `oxygen_columns_add`, `oxygen_tools_plan_table_batch`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"capability":{},"check_technologies":{},"column":{"type":"object","description":"Column definition or prompt override; manual columns need label.","properties":{"label":{"type":"string","minLength":1,"maxLength":200},"key":{"type":"string","description":"snake_case.","maxLength":64},"data_type":{"type":"string","description":"Default text.","enum":["text","numeric","boolean","jsonb","timestamptz","number","json","date","url","email"]},"kind":{"type":"string","description":"Default manual; research=Web Research Agent, ai=row prompts. bind=CRM records; lookup=other Table; oxygen_tables_relate links two.","enum":["manual","source","ai","research","tool","formula","enrichment","bind","lookup"]},"semantic_type":{"type":"string","maxLength":80},"type":{"type":"string","description":"Field type; choice types take definition.options.","enum":["text","number","checkbox","date","json","markdown","image","select","multi_select","status"]},"definition":{"type":"object","description":"toolId accepts tools-search ids, including composio.*.","properties":{"mode":{"type":"string","enum":["native","first_match","count","exists","aggregate"]},"toolId":{"type":"string"},"credentialMode":{"type":"string","enum":["managed","user_api_key","user_oauth"]},"inputMapping":{"type":"object","description":"Inputs.","additionalProperties":{"oneOf":[{"type":"string","description":"Column key"},{"type":"object","properties":{"type":{"type":"string","enum":["column","literal","template"],"description":"columnKey; nested refs; {{key}} template."},"columnKey":{"type":"string"},"column_key":{"type":"string"}},"additionalProperties":true}]}},"prompt":{"type":"string","description":"{{column_key}}."},"model":{"type":"string","description":"Managed allowlist; BYOK any."},"reasoningLevel":{"type":"string","enum":["low","medium","high"]},"runCondition":{"type":"object","description":"Truthy.","properties":{"type":{"type":"string","enum":["formula"]},"expression":{"type":"string"},"referencedColumns":{"type":"array","description":"Expression's snake_case keys.","items":{"type":"string"}}},"required":["type","expression"],"additionalProperties":true},"options":{"type":"array","description":"Choice-column options; cells store value.","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"color":{"type":"string","enum":["gray","red","orange","amber","yellow","green","teal","blue","indigo","purple","pink"]},"order":{"type":"integer"}},"required":["value"],"additionalProperties":true}},"decision":{"type":"object","description":"Classify for 0.075 credits/row; prompt names evidence as {{column_key}}.","properties":{"mode":{"type":"string","enum":["labels","yes_no","score"]},"labels":{"type":"array","items":{"type":"string"}},"levels":{"type":"array","description":"Lowest first.","items":{"type":"string"}},"grounding":{"type":"string","enum":["none","workspace"]},"minConfidence":{"type":"number"}},"required":["mode"]}},"additionalProperties":true},"capability":{"type":"string","description":"Define-only enrichment seed; verify_email grades an existing address.","enum":["verify_email","work_email","personal_email","mobile_phone","linkedin_url"]},"include_personal_email":{"type":"boolean","description":"work_email only: also find the personal email, into the cell's personal_email."}},"additionalProperties":true},"fields":{},"includePersonalEmail":{},"include_personal_email":{},"input_mapping":{"type":"object","description":"Same shapes as column.definition.inputMapping.","additionalProperties":true},"inputs":{"type":"object","additionalProperties":{"type":"string"}},"key":{"type":"string","maxLength":64},"payload_column":{},"preset":{"type":"string","enum":["person_enrich","company_enrich","company_tech_stack","company_funding","company_revenue","company_hiring","company_lookalikes","domain_check"]},"promptKey":{},"prompt_key":{"type":"string","maxLength":80},"researchDepth":{"type":"string","enum":["quick","standard","deep"]},"research_depth":{},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_add","oxygen_tools_plan_table_batch"]}},"/api/cli/tables/columns/catalog":{"get":{"operationId":"getTablesColumnsCatalog","tags":["Tables"],"summary":"Column Template Catalog","description":"Lists column templates for oxygen_columns_add prompt_key, with the input each reads and its credits per row. Filter by category, kind, search, family. Bundles (preset): oxygen_enrichment_catalog.\n\nMCP: `oxygen_columns_catalog`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"category","in":"query","required":false,"schema":{"type":"string","description":"Picker section, e.g. extract, people or company; comma-separate to combine.","maxLength":80}},{"name":"family","in":"query","required":false,"schema":{"type":"string","description":"Sub-group inside a category.","maxLength":80}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["ai","research","formula","search","tool"]}},{"name":"q","in":"query","required":false,"schema":{}},{"name":"search","in":"query","required":false,"schema":{"type":"string","description":"Matches key/title/description.","maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_columns_catalog"]}},"/api/cli/tables/columns/convert":{"post":{"operationId":"postTablesColumnsConvert","tags":["Tables"],"summary":"Update Column","description":"Updates a column's label, semantic type or definition (definition shallow merges: arrays and objects like definition.options or a lookup's match are replaced whole). AI prompts read {{column_key}} or inputMapping {{name}}; unknown → invalid_prompt_column + near misses. convertTo agent (Web Research Agent)|ai|keyword rebuilds it, clearing results; needs confirm.\n\nMCP: `oxygen_columns_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string","description":"ID or key.","minLength":1,"maxLength":200},"confirm":{"type":"boolean"},"dry_run":{"type":"boolean","description":"Return the would-be merged definition without writing."},"prompt":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"to":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_update"]}},"/api/cli/tables/columns/delete":{"post":{"operationId":"postTablesColumnsDelete","tags":["Tables"],"summary":"Delete Column","description":"Deletes a column: archives now, frees the key, physically purges after a window (default 14d; restorable via oxygen_columns_restore until then). now=true purges immediately and permanently: first call 409s with a preview (cells, dependents), repeat with approved=true.\n\nMCP: `oxygen_columns_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Approve the previewed immediate purge."},"column":{"type":"string","description":"ID or key.","minLength":1,"maxLength":200},"columnKey":{},"column_key":{},"columns":{"type":"array","minItems":1,"items":{"type":"string","description":"ID or key.","minLength":1,"maxLength":200},"description":"Batch of exact columns; alternative to column."},"now":{"type":"boolean","description":"Purge immediately (irreversible; needs approved=true)."},"purge_after_days":{"type":"number","description":"Days until purge. Default 14; 0 = next sweep."},"reason":{"type":"string","description":"Audit-trail note."},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_delete"]}},"/api/cli/tables/columns/deps":{"get":{"operationId":"getTablesColumnsDeps","tags":["Tables"],"summary":"Column Dependency Graph","description":"Read-only column dependency graph: formula/input-mapping/run-condition/waterfall edges, transitive up+downstream, cycles — what breaks if a column changes.\n\nMCP: `oxygen_columns_deps`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"column","in":"query","required":false,"schema":{"type":"string","description":"Focus on one column key.","maxLength":200}},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"Table id or slug.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_columns_deps"]}},"/api/cli/tables/columns/fields":{"get":{"operationId":"tables.columns.fields","tags":["Tables"],"summary":"Columns fields","description":"Read the output fields available from one hosted Table column.\n\nMCP: `oxygen_table_column_fields`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":true,"schema":{"type":"string"}},{"name":"column","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_column_fields"]}},"/api/cli/tables/columns/rename":{"post":{"operationId":"postTablesColumnsRename","tags":["Tables"],"summary":"Rename Column","description":"Renames a column's stable key (key required); for a label-only change, use oxygen_columns_update with label. Costs 0 credits; read back with oxygen_tables_describe.\n\nMCP: `oxygen_columns_rename`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string","description":"ID or key.","minLength":1,"maxLength":200},"key":{"type":"string","description":"New snake_case key.","minLength":1,"maxLength":64},"label":{"type":"string","description":"Optional new display label.","maxLength":200},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_rename"]}},"/api/cli/tables/columns/reorder":{"post":{"operationId":"postTablesColumnsReorder","tags":["Tables"],"summary":"Reorder Column","description":"Moves a column to a new 0-based position (0 first; beyond last = end). Values, definitions, and run history are unchanged. dry_run previews.\n\nMCP: `oxygen_columns_reorder`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string","description":"ID or key.","minLength":1,"maxLength":200},"dryRun":{},"dry_run":{"type":"boolean","description":"Return the would-be final position without writing."},"position":{"type":"number","description":"0-based target index (>= 0; non-integers floored; beyond last = end).","minimum":0},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_reorder"]}},"/api/cli/tables/columns/restore":{"post":{"operationId":"postTablesColumnsRestore","tags":["Tables"],"summary":"Restore Column","description":"Restores an archived or delete-scheduled column: cancels the purge and renames it back to its original key (usable as the ref).\n\nMCP: `oxygen_columns_restore`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string","description":"ID or key.","minLength":1,"maxLength":200},"columnKey":{},"column_key":{},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_columns_restore"]}},"/api/cli/tables/columns/run":{"post":{"operationId":"postTablesColumnsRun","tags":["Tables"],"summary":"Run Tool/AI Column","description":"Runs a column on selected rows. Preview, then pass approved=true + max_credits. limit fills empties. Large runs: execution_status=planning.\n\nMCP: `oxygen_columns_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"approved=true to run paid background runs after a dry run or preview."},"approved_effect_unknown":{},"background":{"type":"boolean","description":"For free deterministic columns, choose background vs inline. Paid AI/tool/enrichment/custom-HTTP execution is always durable background work; false cannot force it inline."},"column":{"type":"string","description":"ID or key.","minLength":1,"maxLength":200},"columnId":{},"columnKey":{},"column_id":{},"column_key":{},"connectionId":{},"connection_id":{"type":"string","description":"Optional integration connection id override."},"dryRun":{},"dry_run":{"type":"boolean","description":"Preview the model tier, credit estimate, and posture without spending."},"force":{"type":"boolean","description":"Re-run even if cells are already populated."},"idempotencyKey":{},"idempotency_key":{"type":"string","maxLength":200},"limit":{"type":"integer","description":"Run the next N rows whose target cell is still empty (force=true: the first N regardless). Shortcut for selection={mode:'limit', limit:N}.","minimum":1,"maximum":500},"max_concurrency":{"type":"integer","minimum":1,"maximum":4000},"max_credits":{"type":"number","description":"Safety ceiling for managed model/provider/web-grounding credits. BYOK covers the model call only; managed grounding still needs this ceiling. Unused credits are not spent.","minimum":0},"rowId":{},"row_id":{"type":"string","description":"Run for a single row id. Mutually exclusive with limit."},"selection":{"type":"object","description":"Select all, limit, row_ids, or filter rows.","properties":{"mode":{"type":"string","enum":["all","limit","row_ids","filter"]},"limit":{"type":"integer","minimum":1,"maximum":1000000},"row_ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":1000000},"filters":{"type":"array","items":{"type":"object","description":"Simple server-side row filter.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","contains","not_contains","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"minItems":1,"maxItems":20},"formula_values":{"type":"string","enum":["materialized"],"description":"Default is refused. Force-rerun the selector formula first (0 credits), then use this stored-snapshot mode."}},"required":["mode"]},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_run"]}},"/api/cli/tables/columns/update":{"post":{"operationId":"postTablesColumnsUpdate","tags":["Tables"],"summary":"Update Column","description":"Updates a column's label, semantic type or definition (definition shallow merges: arrays and objects like definition.options or a lookup's match are replaced whole). AI prompts read {{column_key}} or inputMapping {{name}}; unknown → invalid_prompt_column + near misses. convertTo agent (Web Research Agent)|ai|keyword rebuilds it, clearing results; needs confirm.\n\nMCP: `oxygen_columns_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"alwaysShow":{},"always_show":{"type":"boolean","description":"Keep visible in the grid even when empty, for everyone. false unpins."},"column":{"type":"string","description":"ID or key.","minLength":1,"maxLength":200},"dataType":{},"data_type":{"type":"string","enum":["text","numeric","boolean","jsonb","timestamptz"],"description":"Lookup columns only; follows the mode when omitted. Discards cached cells."},"definition":{"type":"object","description":"toolId accepts tools-search ids, including composio.*.","properties":{"mode":{"type":"string","enum":["native","first_match","count","exists","aggregate"]},"toolId":{"type":"string"},"credentialMode":{"type":"string","enum":["managed","user_api_key","user_oauth"]},"inputMapping":{"type":"object","description":"Inputs.","additionalProperties":{"oneOf":[{"type":"string","description":"Column key"},{"type":"object","properties":{"type":{"type":"string","enum":["column","literal","template"],"description":"columnKey; nested refs; {{key}} template."},"columnKey":{"type":"string"},"column_key":{"type":"string"}},"additionalProperties":true}]}},"prompt":{"type":"string","description":"{{column_key}}."},"model":{"type":"string","description":"Managed allowlist; BYOK any."},"reasoningLevel":{"type":"string","enum":["low","medium","high"]},"runCondition":{"type":"object","description":"Truthy.","properties":{"type":{"type":"string","enum":["formula"]},"expression":{"type":"string"},"referencedColumns":{"type":"array","description":"Expression's snake_case keys.","items":{"type":"string"}}},"required":["type","expression"],"additionalProperties":true},"options":{"type":"array","description":"Choice-column options; cells store value.","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"color":{"type":"string","enum":["gray","red","orange","amber","yellow","green","teal","blue","indigo","purple","pink"]},"order":{"type":"integer"}},"required":["value"],"additionalProperties":true}}},"additionalProperties":true},"definitionUnset":{},"definition_unset":{"type":"array","items":{"type":"string"},"description":"Definition keys to delete after the merge (e.g. [\"outputSchema\",\"model\"]). Lifecycle/provenance keys are rejected."},"dryRun":{},"dry_run":{"type":"boolean","description":"Return the would-be merged definition without writing."},"hiddenByDefault":{},"hidden_by_default":{"type":"boolean","description":"Hide in the grid on first open; other surfaces still return it. false shows it."},"label":{"type":"string","maxLength":200},"options":{"type":"array","description":"Replaces a choice column's options.","items":{}},"position":{"type":"integer","minimum":0},"researchDepth":{"type":"string","enum":["quick","standard","deep"]},"research_depth":{},"semanticType":{},"semantic_type":{"oneOf":[{"type":"string","maxLength":80},{"type":"null"}],"description":"null clears."},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_columns_update"]}},"/api/cli/tables/dedupe/apply":{"post":{"operationId":"postTablesDedupeApply","tags":["Tables"],"summary":"Dedupe Rows","description":"Collapse duplicate rows by normalized (email/domain/linkedin) or fuzzy_label keys. dry_run previews groups; dry_run=false + approved=true deletes losers (kept in row history for 30 days).\n\nMCP: `oxygen_tables_dedupe`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"against_column":{},"against_table":{},"approved":{"type":"boolean","description":"Confirm the deletion."},"column":{},"keep":{"type":"string","description":"Survivor per group.","enum":["oldest","newest","most_complete"]},"keys":{"type":"array","description":"1-2 key columns for the match (composite when 2).","items":{"type":"object","properties":{"column":{"type":"string","description":"Column key."},"normalizer":{"type":"string","description":"Match mode.","enum":["exact","email","domain","linkedin_url","fuzzy_label"]}},"required":["column"]},"minItems":1,"maxItems":2},"merge_values":{"type":"string","description":"Fill survivor blanks from losers first.","enum":["none","fill_empty"]},"normalizer":{},"scan_limit":{"type":"integer","description":"Max rows to scan.","minimum":1},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_dedupe"]}},"/api/cli/tables/dedupe/cross-check":{"post":{"operationId":"postTablesDedupeCrossCheck","tags":["Tables"],"summary":"Cross-Table Dedupe Check","description":"Read-only: report rows in one table whose normalized key value already exists in another table (e.g. leads already in the CRM). No fuzzy matching.\n\nMCP: `oxygen_tables_dedupe_cross_check`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"against_column":{"type":"string","description":"Key column in against_table.","minLength":1},"against_table":{"type":"string","description":"Other table id or slug.","minLength":1},"approved":{},"column":{"type":"string","description":"Key column in table.","minLength":1},"keep":{},"keys":{},"merge_values":{},"normalizer":{"type":"string","description":"Match mode.","enum":["exact","email","domain","linkedin_url"]},"scan_limit":{"type":"integer","description":"Max rows to scan.","minimum":1},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_dedupe_cross_check"]}},"/api/cli/tables/dedupe/preview":{"post":{"operationId":"postTablesDedupePreview","tags":["Tables"],"summary":"Dedupe Rows","description":"Collapse duplicate rows by normalized (email/domain/linkedin) or fuzzy_label keys. dry_run previews groups; dry_run=false + approved=true deletes losers (kept in row history for 30 days).\n\nMCP: `oxygen_tables_dedupe`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"against_column":{},"against_table":{},"approved":{"type":"boolean","description":"Confirm the deletion."},"column":{},"keep":{"type":"string","description":"Survivor per group.","enum":["oldest","newest","most_complete"]},"keys":{"type":"array","description":"1-2 key columns for the match (composite when 2).","items":{"type":"object","properties":{"column":{"type":"string","description":"Column key."},"normalizer":{"type":"string","description":"Match mode.","enum":["exact","email","domain","linkedin_url","fuzzy_label"]}},"required":["column"]},"minItems":1,"maxItems":2},"merge_values":{"type":"string","description":"Fill survivor blanks from losers first.","enum":["none","fill_empty"]},"normalizer":{},"scan_limit":{"type":"integer","description":"Max rows to scan.","minimum":1},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_dedupe"]}},"/api/cli/tables/delete":{"post":{"operationId":"postTablesDelete","tags":["Tables"],"summary":"Delete Table","description":"Archives a table, frees its slug; oxygen_tables_restore recovers it before purge (default 14 days). now=true purges permanently: preview (409), then approved=true; a large table returns purging.\n\nMCP: `oxygen_tables_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Approve the previewed immediate purge."},"now":{"type":"boolean","description":"Purge immediately (irreversible; needs approved=true)."},"purge_after_days":{"type":"number","description":"Days until purge. Default 14; 0 = next sweep."},"reason":{"type":"string","description":"Audit-trail note."},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"table_id":{},"tables":{"type":"array","minItems":1,"items":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"description":"Batch of exact tables; alternative to table."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_delete"]}},"/api/cli/tables/describe":{"post":{"operationId":"postTablesDescribe","tags":["Tables"],"summary":"Describe Table","description":"Reads columns, types and config; `column` returns one. A UUID in another accessible org returns `table_in_other_org`; select the org in `details.recovery` with `oxygen_orgs_select`, then retry.\n\nMCP: `oxygen_tables_describe`, `oxygen_tools_plan_table_batch`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"type":"string"},"include_archived":{"type":"boolean","description":"Include archived columns and read a deleted (archived or purge-scheduled) table."},"include_stats":{"type":"boolean","description":"Free row count + fill rates; summary.statsSampled=true when sampled."},"table":{"type":"string","description":"ID, slug, or Table URL.","minLength":1,"maxLength":400}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_describe","oxygen_tools_plan_table_batch"]}},"/api/cli/tables/favorite":{"get":{"operationId":"tables.favorites.get","tags":["Tables"],"summary":"Tables favorites","description":"Read starred Tables/folders (per-member preference; free (0 credits)); next_cursor. Catalog stars differ.\n\nCLI: `oxygen tables favorites`.\n\nMCP: `oxygen_tables_favorites`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"details","in":"query","required":false,"schema":{"type":"boolean","description":"Kind, id, name and web_url."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"description":"Page size (default 20)."}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","maxLength":512,"description":"next_cursor; restart if stars change."}},{"name":"max_chars","in":"query","required":false,"schema":{"type":"integer","minimum":500,"maximum":10000,"description":"Response cap."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_favorites"],"x-oxygen-cli-command":"oxygen tables favorites"},"post":{"operationId":"tables.favorite.set","tags":["Tables"],"summary":"Tables favorite","description":"Star/unstar exactly one table or folder (saved per-member preference). Free (0 credits). Catalog stars differ.\n\nCLI: `oxygen tables favorite`.\n\nMCP: `oxygen_tables_favorite`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table":{"type":"string","minLength":1,"description":"Table id, slug or same-workspace URL. Pass exactly one of table or folder."},"folder":{"type":"string","minLength":1,"description":"Folder id or slug. Pass exactly one of table or folder."},"favorite":{"type":"boolean","description":"true stars; false unstars."}},"required":["favorite"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_favorite"],"x-oxygen-cli-command":"oxygen tables favorite"}},"/api/cli/tables/feeds":{"get":{"operationId":"getTablesFeeds","tags":["Tables"],"summary":"Get Table Feed","description":"Read one stored feed. summary omits long settings; value returns lossless public JSON fragments at path (JSON Pointer, empty=root). Resume value_cursor with identical feed/path/include flags; source changes refuse. Omit window controls for legacy full output. Free.\n\nMCP: `oxygen_feeds_get`, `oxygen_feeds_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"feed","in":"query","required":false,"schema":{"type":"string","description":"Feed id or endpoint id.","minLength":1,"maxLength":200}},{"name":"feedId","in":"query","required":false,"schema":{}},{"name":"feed_id","in":"query","required":false,"schema":{}},{"name":"include","in":"query","required":false,"schema":{}},{"name":"limit","in":"query","required":false,"schema":{}},{"name":"run_state","in":"query","required":false,"schema":{}},{"name":"state","in":"query","required":false,"schema":{}},{"name":"status","in":"query","required":false,"schema":{}},{"name":"table","in":"query","required":false,"schema":{}},{"name":"transport","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_feeds_get","oxygen_feeds_list"]},"post":{"operationId":"postTablesFeeds","tags":["Tables"],"summary":"Bind Table Feed","description":"Binds a table feed: pull (default) freezes a primary request plus optional fallback lanes (cadence requires one executable lane); push (row_schema) mints a webhook that refuses rows not matching the schema (typed or rejected).\nWEB INTENT: feed_kind=rb2b + transport=push lands the website-visit reveals Oxygen already receives (still Signals too) as rows; free, fixed shape, table or create_table only.\nCOST: binding and push deliveries are free; an armed cadence spends credits on every cycle, forever, so it requires sync.every + sync.max_credits_per_cycle + approved=true together.\nREFUSALS: feed_not_incremental means the bound provider cannot resume where it left off (Apollo, TheirStack company search, PredictLeads market-wide funding/news), so a cadence would re-buy the same rows every cycle — that feed is one-shot only.\nFOLLOW-UP: oxygen_signals_search_plan / oxygen_companies_search_plan -> oxygen_feeds_bind -> oxygen_feeds_run (mode=dry_run) -> oxygen_feeds_get.\n\nMCP: `oxygen_feeds_bind`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Approve the recurring paid pull. Required alongside sync.every and sync.max_credits_per_cycle."},"auth_mode":{"type":"string","description":"Push: default secret.","enum":["secret","none"]},"cadence":{},"create_table":{"type":"object","description":"Push: create a table from row_schema instead.","properties":{"name":{"type":"string"},"project":{"type":"string"}}},"cursorPath":{},"cursorRequestKey":{},"cursor_path":{},"cursor_request_key":{},"event_id_path":{"type":"string"},"event_type_path":{"type":"string"},"every":{},"feedKind":{},"feed_kind":{"type":"string","description":"Pull: what this feed sources, or rb2b for the push-only web-intent feed (fixed reveal shape: no row_schema, route or cadence).","enum":["company_search","signal_search","rb2b"]},"filters":{"type":"object","description":"Typed filters recorded on the feed for provenance and re-planning.","additionalProperties":true},"focus_top_k":{},"include_active_enrollments":{},"inputShape":{},"input_shape":{"type":"string","description":"Routing-registry input shape from the plan, e.g. market or watch_list."},"intentId":{},"intent_id":{"type":"string","description":"Routing-registry intent id from the plan."},"items_path":{"type":"string","description":"Push: dot path to the row array."},"lanes":{},"maxCredits":{},"maxCreditsPerCycle":{},"maxPages":{},"maxRowsPerCycle":{},"max_credits":{},"max_credits_per_cycle":{},"max_pages":{},"max_rows_per_cycle":{},"name":{"type":"string","description":"Display name for the feed.","maxLength":200},"occurred_at_path":{"type":"string"},"prompt":{},"registryVersion":{},"registry_version":{"type":"string","description":"Routing-registry revision from the plan, retained with the frozen feed provenance."},"request":{},"route":{"type":"object","description":"Pull: copy tool_id + request and optional fallback lanes from the matching plan route (oxygen_signals_search_plan or oxygen_companies_search_plan). Omitted rows_path uses response.results; missing paths try common response arrays, empty arrays stay empty. Omitted row_mapping keeps object rows. Omit upsert_key to insert; set it to upsert.","additionalProperties":false,"properties":{"tool_id":{"type":"string","description":"Provider tool id the cycle calls, e.g. blitzapi.job_search.","minLength":1,"maxLength":200},"request":{"type":"object","description":"Provider request body for that tool.","additionalProperties":true},"tool_ids":{"type":"array","description":"Cascade of tool ids to try in order. Defaults to [tool_id].","items":{"type":"string"}},"lanes":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"tool_id":{"type":"string","minLength":1},"request":{"type":"object","additionalProperties":true},"rows_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"row_mapping":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"cursor_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"cursor_request_key":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["tool_id","request"]},"minItems":1,"description":"Distinct executable provider requests, primary first. When using multiple lanes, omit the cadence."},"rows_path":{"type":"string","description":"Dot path to the row array in the provider response."},"row_mapping":{"type":"object","description":"Table column key -> provider field path.","additionalProperties":true},"cursor_path":{"type":"string","description":"Dot path to the next-page cursor in the provider response."},"cursor_request_key":{"type":"string","description":"Request key that receives the next cursor."},"max_pages":{"type":"integer","description":"Maximum provider pages per cycle. Defaults to 1.","minimum":1},"upsert_key":{"type":"string","description":"Column key rows upsert on, so a cycle updates instead of duplicating."}},"required":["tool_id","request"]},"routeId":{},"route_id":{"type":"string","description":"Route id from the plan this feed was bound from."},"rowMapping":{},"rowSchema":{},"row_mapping":{},"row_schema":{"type":"object","description":"Push: JSON Schema for one row (only type/properties/required/additionalProperties/items/enum/const/anyOf). A non-matching delivery is refused with 422 and ledgered; nothing is written."},"rowsPath":{},"rows_path":{},"source":{},"source_prompt":{"type":"string","description":"The prompt this feed was planned from.","maxLength":20000},"sync":{"type":"object","description":"Cadence and per-cycle ceilings. Omit to leave the feed disarmed (stored, nothing runs).","additionalProperties":false,"properties":{"every":{"type":"string","description":"Cadence: hourly, every_6h, daily@<hour>, or weekly@<day><hour> (e.g. weekly@mon9). Hours are 0-23 UTC. Arming a cadence on a paid provider is a STANDING spend grant."},"max_credits_per_cycle":{"type":"number","description":"Credit ceiling PER sync cycle. Required with approved=true to arm a cadence on a paid provider.","minimum":0},"max_rows_per_cycle":{"type":"integer","description":"Advisory row ceiling per cycle, recorded on each cycle's run provenance.","minimum":1}}},"table":{"type":"string","description":"Table id or slug that receives the rows.","minLength":1,"maxLength":400},"toolId":{},"toolIds":{},"tool_id":{},"tool_ids":{},"transport":{"type":"string","enum":["pull","push"]},"upsertKey":{},"upsert_key":{"type":"string","description":"Push: upsert column."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_feeds_bind"]},"patch":{"operationId":"tables.feeds.update","tags":["Tables"],"summary":"Pause Table Feed","description":"Update an existing Table feed in place; changed cadence, increased cap or source scope can require renewed standing authorization.\n\nMCP: `oxygen_feeds_pause`, `oxygen_feeds_resume`, `oxygen_feeds_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"feed":{"type":"string","minLength":1},"name":{"type":"string"},"status":{"type":"string","enum":["active","disabled"]},"run_state":{"type":"string","enum":["idle","running","error","exhausted"]},"sync":{"type":"object","description":"Omitted fields keep their values.","additionalProperties":false,"properties":{"every":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"hourly, every_6h, daily@<0-23>, weekly@<day><hour>; UTC. null removes the cron."},"max_credits_per_cycle":{"type":"number","exclusiveMinimum":0,"description":"Future-cycle ceiling; configuration spends nothing."},"max_rows_per_cycle":{"type":"integer","minimum":1}}},"route":{"type":"object","additionalProperties":false,"properties":{"tool_id":{"type":"string","minLength":1},"request":{"type":"object","additionalProperties":true},"rows_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"row_mapping":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"cursor_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"cursor_request_key":{"oneOf":[{"type":"string"},{"type":"null"}]},"tool_ids":{"type":"array","items":{"type":"string","minLength":1}},"lanes":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"tool_id":{"type":"string","minLength":1},"request":{"type":"object","additionalProperties":true},"rows_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"row_mapping":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"cursor_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"cursor_request_key":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["tool_id","request"]},"minItems":1},"max_pages":{"type":"integer","minimum":1},"upsert_key":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["tool_id","request"],"description":"Full frozen route from feeds_get(include_route=true). Replacement resets cursor/error. Scheduled replacements require one executable lane; distinct fallbacks require no cadence."},"filters":{"type":"object","additionalProperties":true},"intent_id":{"type":"string"},"input_shape":{"type":"string"},"route_id":{"type":"string"},"registry_version":{"type":"string"},"source_prompt":{"type":"string"},"approved":{"type":"boolean","description":"Human authorization for expanded recurring scope; a free config call grants no future spend."}},"required":["feed"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_feeds_pause","oxygen_feeds_resume","oxygen_feeds_update"]},"delete":{"operationId":"deleteTablesFeeds","tags":["Tables"],"summary":"Unbind Table Feed","description":"Deletes a feed: removes its cron FIRST, then the feed row, so no orphan cron can keep spending at a feed that no longer exists. The table and every row the feed already wrote are kept. Free.\n\nMCP: `oxygen_feeds_unbind`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"feed":{"type":"string","minLength":1},"name":{"type":"string"},"status":{"type":"string","enum":["active","disabled"]},"run_state":{"type":"string","enum":["idle","running","error","exhausted"]},"sync":{"type":"object","description":"Omitted fields keep their values.","additionalProperties":false,"properties":{"every":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"hourly, every_6h, daily@<0-23>, weekly@<day><hour>; UTC. null removes the cron."},"max_credits_per_cycle":{"type":"number","exclusiveMinimum":0,"description":"Future-cycle ceiling; configuration spends nothing."},"max_rows_per_cycle":{"type":"integer","minimum":1}}},"route":{"type":"object","additionalProperties":false,"properties":{"tool_id":{"type":"string","minLength":1},"request":{"type":"object","additionalProperties":true},"rows_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"row_mapping":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"cursor_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"cursor_request_key":{"oneOf":[{"type":"string"},{"type":"null"}]},"tool_ids":{"type":"array","items":{"type":"string","minLength":1}},"lanes":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"tool_id":{"type":"string","minLength":1},"request":{"type":"object","additionalProperties":true},"rows_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"row_mapping":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"cursor_path":{"oneOf":[{"type":"string"},{"type":"null"}]},"cursor_request_key":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["tool_id","request"]},"minItems":1},"max_pages":{"type":"integer","minimum":1},"upsert_key":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["tool_id","request"],"description":"Full frozen route from feeds_get(include_route=true). Replacement resets cursor/error. Scheduled replacements require one executable lane; distinct fallbacks require no cadence."},"filters":{"type":"object","additionalProperties":true},"intent_id":{"type":"string"},"input_shape":{"type":"string"},"route_id":{"type":"string"},"registry_version":{"type":"string"},"source_prompt":{"type":"string"},"approved":{"type":"boolean","description":"Human authorization for expanded recurring scope; a free config call grants no future spend."}},"required":["feed"]}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_feeds_unbind"]}},"/api/cli/tables/feeds/run":{"post":{"operationId":"postTablesFeedsRun","tags":["Tables"],"summary":"Run Table Feed Cycle","description":"Runs one sync cycle now, through the feed's own cron workflow — one harvest path, one lease, one cursor.\nCOST: mode=dry_run (default) is free and renders the exact next-cycle provider request with the cursor or watermark already injected. mode=live spends credits and requires approved=true and max_credits.\nREFUSALS: feed_not_scheduled means the feed has no armed cadence, so there is no cycle to run — arm one with oxygen_feeds_bind, or use the search run surface for a one-shot pull. table_feed_paused means resume it first.\n\nMCP: `oxygen_feeds_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required for a live cycle after inspecting the dry run."},"feed":{"type":"string","description":"Feed id or endpoint id.","minLength":1,"maxLength":200},"feedId":{},"feed_id":{},"max_credits":{"type":"number","description":"Required credit ceiling for a live cycle.","minimum":0},"mode":{"type":"string","description":"dry_run (default, free) or live.","enum":["dry_run","live"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_feeds_run"]}},"/api/cli/tables/formulas/functions":{"get":{"operationId":"getTablesFormulasFunctions","tags":["Tables"],"summary":"List Formula Functions","description":"Lists the formula function library (signatures, examples) and operator grammar — the language of formula columns and per-column run conditions (only-run-if). Verify drafts with oxygen_formulas_validate.\n\nMCP: `oxygen_formulas_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_formulas_list"]}},"/api/cli/tables/formulas/validate":{"post":{"operationId":"postTablesFormulasValidate","tags":["Tables"],"summary":"Validate Formula Against Table","description":"Validates a formula against a table and previews sample-row output — free, no writes. Returns valid:false with parse error / unknown columns, or valid:true with per-row samples. Loop: draft → validate → attach via oxygen_columns_add (kind=formula) or as runCondition.\n\nMCP: `oxygen_formulas_validate`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"expression":{"type":"string","description":"Formula, e.g. if(score > 80, \"hot\", \"warm\").","minLength":1,"maxLength":8000},"rowIds":{},"row_ids":{"type":"array","description":"Specific row ids (max 25).","items":{"type":"string"},"maxItems":25},"sampleLimit":{},"sample_limit":{"type":"number","description":"Sample rows to evaluate (0-25, default 5).","minimum":0,"maximum":25},"slug":{},"table":{"type":"string","description":"Table id or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_formulas_validate"]}},"/api/cli/tables/hubspot-import":{"get":{"operationId":"getTablesHubspotImport","tags":["Tables"],"summary":"List HubSpot Import Sources","description":"List a connected HubSpot account's saved contact/company lists and identity properties for table or Records imports. Definitions only; 0 credits, uses HubSpot API quota.\n\nMCP: `oxygen_tables_hubspot_lists`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"connection_id","in":"query","required":false,"schema":{"type":"string","description":"Defaults to the first connected account."}},{"name":"query","in":"query","required":false,"schema":{"type":"string","description":"List-name search."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_hubspot_lists"]},"post":{"operationId":"postTablesHubspotImport","tags":["Tables"],"summary":"Import from HubSpot","description":"Import HubSpot contacts/companies into a new table or Records after DNC sync. Never enrolls or sends. Live requires approval and the exact dry-run fingerprint.\n\nMCP: `oxygen_tables_hubspot_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"company_dnc_list_id":{"type":"string","description":"Company list suppressed organization-wide."},"company_domain_property":{"type":"string","description":"Defaults to domain."},"company_linkedin_property":{"type":"string"},"connection_id":{"type":"string","description":"Default: first connected account."},"contactProperties":{},"contact_company_domain_property":{"type":"string"},"contact_company_linkedin_property":{"type":"string"},"contact_linkedin_property":{"type":"string"},"contact_properties":{"type":"array","items":{"type":"string"},"maxItems":50},"cron":{"type":"string"},"destination":{"type":"string","enum":["table","records"],"description":"Defaults to table."},"dnc_list_id":{"type":"string","description":"Contact list suppressed before import."},"idempotency_key":{"type":"string"},"lead_list_id":{"type":"string","description":"Omit with object to import all records."},"live":{},"maxRecordsPerList":{},"max_credits":{"type":"number","exclusiveMinimum":0},"max_records_per_list":{"type":"integer","minimum":1,"description":"Optional record limit; omit for all."},"mode":{"type":"string","enum":["dry_run","live"]},"object":{"type":"string","enum":["contacts","companies"],"description":"Required without lead_list_id; default contacts."},"project":{"type":"string","description":"Project id or slug. Defaults to General."},"refresh":{"type":"string","enum":["once","scheduled"],"description":"Defaults to scheduled."},"reviewed_fingerprint":{"type":"string"},"sample":{"type":"boolean","description":"Dry-run only: read up to 50 real records using HubSpot API quota. No writes; omitted means no reads."},"table_name":{"type":"string","description":"New table name."},"timezone":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_hubspot_import"]}},"/api/cli/tables/import":{"post":{"operationId":"tables.resource.import","tags":["Tables"],"summary":"Tables upload","description":"Preview or import small uploaded CSV, JSON or XLSX bytes through the exact browser import contract. Preview writes no rows.\n\nCLI: `oxygen tables upload`.\n\nMCP: `oxygen_table_resource_upload`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"content_base64":{"type":"string"},"file_name":{"type":"string"},"content_type":{"type":"string"},"intent":{"type":"string","enum":["preview","import"]},"format":{"type":"string","enum":["csv","json","xlsx"]},"sheet":{"type":"string"},"table":{"type":"string"},"create_name":{"type":"string"},"project":{"type":"string"},"upsert_key":{"type":"string"},"source_key_map":{"type":"object","additionalProperties":true}},"required":["content_base64","file_name"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_resource_upload"],"x-oxygen-cli-command":"oxygen tables upload"}},"/api/cli/tables/import-csv":{"post":{"operationId":"tables.import.csv","tags":["Tables"],"summary":"Import CSV","description":"Import inline CSV into a hosted Table through its durable ingestion run. Use staged upload for large files.\n\nCLI: `oxygen tables import-csv`.\n\nMCP: `oxygen_tables_import_csv`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"csv_text":{"type":"string"},"csv_base64":{"type":"string"},"table":{"type":"string"},"table_name":{"type":"string"},"project":{"type":"string"},"filename":{"type":"string"},"upsert_key":{"type":"string"},"skip_blank_cells":{"type":"boolean","description":"Keep existing values where a cell is blank."},"batch_size":{"type":"integer","minimum":1,"maximum":5000}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_import_csv"],"x-oxygen-cli-command":"oxygen tables import-csv"}},"/api/cli/tables/import-file":{"post":{"operationId":"tables.import.file","tags":["Tables"],"summary":"Tables import file","description":"Import small base64 file bytes through the shared multipart import API; use staged upload for large files.\n\nCLI: `oxygen tables import-file`.\n\nMCP: `oxygen_tables_import_file`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"content_base64":{"type":"string"},"file_name":{"type":"string"},"content_type":{"type":"string"},"table":{"type":"string"},"table_name":{"type":"string"},"project":{"type":"string"},"format":{"type":"string","enum":["csv","json","xlsx"]},"sheet":{"type":"string"},"upsert_key":{"type":"string"},"source_key_map":{"type":"object","additionalProperties":true},"source_hash":{"type":"string"},"batch_size":{"type":"integer","minimum":1,"maximum":5000},"max_concurrency":{"type":"integer","minimum":1}},"required":["content_base64","file_name"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_import_file"],"x-oxygen-cli-command":"oxygen tables import-file"}},"/api/cli/tables/import-from-url":{"post":{"operationId":"postTablesImportFromUrl","tags":["Tables"],"summary":"Import From Link","description":"Imports a public CSV, TSV, JSON, JSONL or XLSX file, or a Google Sheet shared by link or published to the web, into a new or existing table. Server-side fetch (public https hosts, up to 10 MB), 0 credits. mode='preview' (default) returns columns, sample rows and the row count without writing; 'import' queues durable ingestion.\n\nMCP: `oxygen_tables_import_url`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"createName":{},"create_name":{"type":"string","description":"New table name; pass this or table to import.","maxLength":200},"format":{"type":"string","enum":["csv","json","jsonl","xlsx"],"description":"Override the detected format."},"mode":{"type":"string","enum":["preview","import"]},"project":{"type":"string","description":"New table project id/slug; default General.","maxLength":200},"project_id":{},"sheet":{"type":"string","description":"XLSX worksheet name; defaults to the first.","maxLength":200},"source":{},"source_url":{},"table":{"type":"string","description":"Existing table id or slug.","maxLength":200},"tableId":{},"table_id":{},"table_name":{},"upsertKey":{},"upsert_key":{"type":"string","description":"Column key for upsert instead of insert.","maxLength":100},"url":{"type":"string","description":"The https link to fetch.","minLength":8,"maxLength":2048}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_import_url"]}},"/api/cli/tables/import-preview":{"post":{"operationId":"tables.import.preview","tags":["Tables"],"summary":"Tables import preview","description":"Preview a staged file's headers, rows and existing-table mapping; writes no imported rows.\n\nCLI: `oxygen tables import-preview`.\n\nMCP: `oxygen_tables_import_preview`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"storage_key":{"type":"string"},"file_name":{"type":"string"},"format":{"type":"string","enum":["csv","json","xlsx"]},"byte_length":{"type":"integer","minimum":1},"table":{"type":"string"},"upsert_key":{"type":"string"}},"required":["storage_key","byte_length"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_import_preview"],"x-oxygen-cli-command":"oxygen tables import-preview"}},"/api/cli/tables/import-staged":{"post":{"operationId":"tables.import.staged","tags":["Tables"],"summary":"Tables import staged","description":"Import a staged file into a table or a new create_name table.\n\nCLI: `oxygen tables import-staged`.\n\nMCP: `oxygen_tables_import_staged`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table":{"type":"string"},"create_name":{"type":"string"},"project":{"type":"string"},"storage_key":{"type":"string"},"storage_bucket":{"type":"string"},"storage_provider":{"type":"string","enum":["s3"]},"file_name":{"type":"string"},"format":{"type":"string","enum":["csv","json","xlsx"]},"sha256":{"type":"string"},"upsert_key":{"type":"string"},"skip_blank_cells":{"type":"boolean","description":"Keep existing values where a cell is blank."},"source_key_map":{"type":"object","additionalProperties":true},"ignore_source_keys":{"type":"array","items":{"type":"string"}},"byte_length":{"type":"integer","minimum":1},"row_count":{"type":"integer","minimum":1},"max_concurrency":{"type":"integer","minimum":1,"maximum":1000},"source":{"type":"string","enum":["cli","mcp","web"]},"batch_size":{"type":"integer","minimum":1,"maximum":5000}},"required":["storage_key","byte_length"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_import_staged"],"x-oxygen-cli-command":"oxygen tables import-staged"}},"/api/cli/tables/import-url":{"post":{"operationId":"tables.import.prepare","tags":["Tables"],"summary":"Tables import upload","description":"Prepare a scoped storage upload for a hosted Table import; uploads and imports are separate, inspectable steps.\n\nCLI: `oxygen tables import-upload`.\n\nMCP: `oxygen_tables_import_upload`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_name":{"type":"string"},"content_type":{"type":"string"},"byte_length":{"type":"integer","minimum":1},"trace_id":{"type":"string"},"format":{"type":"string","enum":["csv","json","xlsx"]}},"required":["file_name","byte_length"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_import_upload"],"x-oxygen-cli-command":"oxygen tables import-upload"}},"/api/cli/tables/link":{"post":{"operationId":"postTablesLink","tags":["Tables"],"summary":"Bulk Link Tables","description":"Bulk relation fill: Oxygen measures which column joins the two tables, infers direction and cardinality, and links every matching row in one background run. Plain tables stay plain and use Tables-owned edges; an existing explicit CRM relationship stays in Records. Previews the measured match rate by default; approved=true queues the write. Free (0 credits). undo_run_id archives one past run's links.\n\nMCP: `oxygen_tables_link_bulk`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Queue the write after inspecting the preview. Omit to preview."},"createMissing":{},"create_missing":{"type":"boolean","description":"Also create target rows for unmatched source rows (or CRM records when filling an existing CRM relationship)."},"dryRun":{},"dry_run":{},"max_concurrency":{"type":"integer","description":"Maximum concurrent row items for the run. Native create_missing runs serialize target-row creation safely.","minimum":1,"maximum":4000},"on":{"type":"string","description":"Column label or key to join on. Defaults to the best-measured match.","maxLength":200},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{},"targetTable":{},"target_table":{},"to":{},"toTable":{},"to_table":{"type":"string","description":"Table id or slug to link to. Required unless undo_run_id is set.","minLength":1,"maxLength":200},"undo":{},"undoRunId":{},"undo_run_id":{"type":"string","description":"A previous link run's workspace_run_id: archives the links it created. Previews unless approved.","maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_link_bulk"]}},"/api/cli/tables/link/suggest":{"post":{"operationId":"tables.link.suggest","tags":["Tables"],"summary":"Tables link suggest","description":"Plan column links and matching row counts between Tables; creates no relation. Apply with tables link --to (MCP oxygen_tables_link_bulk).\n\nCLI: `oxygen tables link-suggest`.\n\nMCP: `oxygen_tables_link_suggest`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table":{"type":"string","minLength":1,"description":"Table id, slug, or Oxygen table URL."},"to":{"type":"string","minLength":1,"description":"Table id, slug, or Oxygen table URL."},"on":{"type":"string","description":"Optional join column key or id."},"scan_limit":{"type":"number","description":"Native planner scan limit; bounded server-side."}},"required":["table","to"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_link_suggest"],"x-oxygen-cli-command":"oxygen tables link-suggest"}},"/api/cli/tables/linkedin-company-followers":{"get":{"operationId":"getTablesLinkedinCompanyFollowers","tags":["Tables"],"summary":"Professional Network Company Followers (ScrapeLi)","description":"Preview, create or inspect a follower order. Table now, rows later. Managed: per follower. Own-key: TOTAL placement/recovery fee ceiling; placement-only cannot recover rows. Retry identical payload/ID. Budget exhaustion lands no partial rows; paid pages may be refetched. ScrapeLi bills separately. Status GET: fee-budgeted own-key only.\n\nMCP: `oxygen_tables_followers`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_followers"]},"post":{"operationId":"postTablesLinkedinCompanyFollowers","tags":["Tables"],"summary":"Professional Network Company Followers (ScrapeLi)","description":"Preview, create or inspect a follower order. Table now, rows later. Managed: per follower. Own-key: TOTAL placement/recovery fee ceiling; placement-only cannot recover rows. Retry identical payload/ID. Budget exhaustion lands no partial rows; paid pages may be refetched. ScrapeLi bills separately. Status GET: fee-budgeted own-key only.\n\nMCP: `oxygen_tables_followers`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["preview","create","status"]},"approved":{},"company_url":{"type":"string"},"credentialMode":{},"credential_mode":{"type":"string","enum":["managed","user_api_key"]},"max_credits":{"type":"number","exclusiveMinimum":0,"description":"TOTAL own-key placement/recovery ceiling."},"name":{"type":"string"},"package":{"type":"string","enum":["Basic","Advanced"]},"project":{"type":"string"},"records":{"type":"number","exclusiveMinimum":0,"description":"Min 100, default 1000."},"request_id":{"type":"string","description":"Stable create UUID; status: original."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_followers"]}},"/api/cli/tables/linkedin-network":{"get":{"operationId":"getTablesLinkedinNetwork","tags":["Tables"],"summary":"LinkedIn Network Capture Status","description":"Shows LinkedIn network capture progress: accounts[] lists every connected account with on (switched on or not), state and connections/followers counts; which accounts are armed, how far each account's read warm-up has ramped, and per-drip state for both halves — including whether each is still doing its first full walk (phase 'backfill') or has switched to the light daily check (phase 'delta') — plus a preview of the table and a deep-link to open it. A capture sitting in 'backfill' for days is working as designed, not stuck. Read-only.\n\nMCP: `oxygen_linkedin_network_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_network_status"]},"post":{"operationId":"postTablesLinkedinNetwork","tags":["Tables"],"summary":"Capture LinkedIn Connections and Followers","description":"Captures everyone already in the workspace's LinkedIn network — 1st-degree connections AND followers — into ONE self-refreshing table, deduped to a single row per person with a Relationship column reading connection, follower, or both. Use this when someone wants their existing network as a list to filter, enrich or enroll from; use oxygen_linkedin_followers_import or the connections import only when they explicitly want one half in its own table. account arms one sender (sender id, connection id, or Unipile account id); omit to arm EVERY connected account. table targets an existing table (id or slug); omit to create/reuse 'LinkedIn Network'. This is a STANDING permission: capture keeps running until oxygen_linkedin_network_pause switches it off, and an account connected later is armed automatically. The result names each account armed (senders[].display_name) — confirm it is the user's own before leaving it running. It fills in over days, not seconds — roughly 2,000 people a day per account on the first pass, only inside that account's own working hours — so report it as started and poll oxygen_linkedin_network_status rather than waiting. A read: nothing is sent and no credits are charged.\n\nMCP: `oxygen_linkedin_network_setup`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional account to capture (sender id, connection id, or Unipile account id). Omit to capture every connected LinkedIn account."},"table":{"type":"string","description":"Optional existing workspace table (id or slug) to capture into. Omit to create/reuse a 'LinkedIn Network' table."},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_network_setup"]}},"/api/cli/tables/linkedin-network/pause":{"post":{"operationId":"postTablesLinkedinNetworkPause","tags":["Tables"],"summary":"Pause LinkedIn Network Capture","description":"Switches LinkedIn network capture off: the worker stops reading that account's connections and followers until oxygen_linkedin_network_setup arms it again. Pass account (sender id, connection id, or Unipile account id) to pause one account — the one armed by mistake, say — or omit it to pause every armed account. The table and its rows stay as they are, and re-arming continues the walk where it stopped. A standalone connections or followers import is not touched. Free; nothing is sent.\n\nMCP: `oxygen_linkedin_network_pause`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional account to pause (sender id, connection id, or Unipile account id). Omit to pause every armed LinkedIn account."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_network_pause"]}},"/api/cli/tables/linkedin-open-invites":{"get":{"operationId":"getTablesLinkedinOpenInvites","tags":["Tables"],"summary":"Open LinkedIn Connection Requests Status","description":"Shows the open connection requests table: accounts[] lists every connected LinkedIn account with on, state and next_read_at, plus a table preview and deep-link.\n\nMCP: `oxygen_linkedin_invitations_status`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_linkedin_invitations_status"]},"post":{"operationId":"postTablesLinkedinOpenInvites","tags":["Tables"],"summary":"Track Open LinkedIn Connection Requests","description":"Keeps one self-updating table of every open LinkedIn connection request on the workspace's own accounts: people who asked to connect (direction received) and requests sent that are still waiting (sent), with the person and the account. Each account is checked about twice a day; a request that disappears is marked accepted when the person is now a connection, otherwise no_longer_pending. Accounts connected later stay off until switched on. Read-only on LinkedIn and 0 credits; report it as started and poll oxygen_linkedin_invitations_status.\n\nMCP: `oxygen_linkedin_invitations_setup`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender id, connection id, or Unipile account id. Omit for every connected LinkedIn account."},"table":{"type":"string","description":"Optional existing table (id or slug). Omit to create/reuse 'LinkedIn Open Connection Requests'."},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_invitations_setup"]}},"/api/cli/tables/linkedin-open-invites/pause":{"post":{"operationId":"postTablesLinkedinOpenInvitesPause","tags":["Tables"],"summary":"Pause Open LinkedIn Connection Requests","description":"Stops checking open connection requests for one account, or every account when account is omitted. The table and its rows stay; oxygen_linkedin_invitations_setup switches it back on. Free; nothing is sent.\n\nMCP: `oxygen_linkedin_invitations_pause`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Optional sender id, connection id, or Unipile account id. Omit for every connected LinkedIn account."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_linkedin_invitations_pause"]}},"/api/cli/tables/linkedin-profile-watcher":{"get":{"operationId":"getTablesLinkedinProfileWatcher","tags":["Tables"],"summary":"Professional Network Post Engagers","description":"Daily LinkedIn profile engagers in one editable table with source posts and employers. Preview is free; create/update/resume need approved, preview_hash and a per-cycle cap. Ask for real profile URLs.\n\nMCP: `oxygen_tables_watcher`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"Table id/slug; not for new preview/create."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_watcher"]},"post":{"operationId":"postTablesLinkedinProfileWatcher","tags":["Tables"],"summary":"Professional Network Post Engagers","description":"Daily LinkedIn profile engagers in one editable table with source posts and employers. Preview is free; create/update/resume need approved, preview_hash and a per-cycle cap. Ask for real profile URLs.\n\nMCP: `oxygen_tables_watcher`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["preview","create","get","update","pause","resume"]},"approved":{"type":"boolean"},"credentialMode":{},"credential_mode":{"type":"string","enum":["managed","user_api_key"],"description":"Your Up2Data key if user_api_key."},"max_credits_per_cycle":{"type":"number","exclusiveMinimum":0,"description":"Omit on preview for recommendation."},"name":{"type":"string"},"preview_hash":{"type":"string"},"profiles":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10},"project":{"type":"string"},"request_id":{"type":"string","description":"Create UUID; reuse on retries, same settings."},"table":{"type":"string","description":"Table id/slug; not for new preview/create."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_watcher"]}},"/api/cli/tables/move":{"post":{"operationId":"postTablesMove","tags":["Tables"],"summary":"Move Table to Project","description":"Move a table to another project with rows, columns, runs and provenance; returns a deep-link.\n\nMCP: `oxygen_tables_move`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","description":"Destination project id or slug.","minLength":1},"projectId":{},"projectSlug":{},"project_id":{},"project_slug":{},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{},"tables":{"type":"array","minItems":1,"items":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"description":"Batch of exact tables; alternative to table."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_move"]}},"/api/cli/tables/pipedrive-import":{"get":{"operationId":"getTablesPipedriveImport","tags":["Tables"],"summary":"List Pipedrive Import Sources","description":"Read connected Pipedrive saved filters and custom-field definitions; no people imported. Four BYOK fees may apply: approve with max_credits. Refusal returns the required cap without provider calls.\n\nMCP: `oxygen_tables_pipedrive_filters`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_pipedrive_filters"]},"post":{"operationId":"postTablesPipedriveImport","tags":["Tables"],"summary":"Import Pipedrive Filter Into a Table","description":"Preview or run a Pipedrive saved people filter into a NEW Oxygen table, once or on a schedule. A named do-not-contact filter syncs first and no row lands unless it succeeds. Never enrolls or sends. Live needs approval and the dry-run fingerprint; no_dnc true imports with no suppression.\n\nMCP: `oxygen_tables_pipedrive_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"},"cron":{"type":"string"},"dnc_filter_id":{"type":"string","description":"People-filter id suppressed before any row is written."},"filter_id":{"type":"string","description":"People-filter id whose persons become rows."},"hydrateOrganizations":{},"hydrate_organizations":{"type":"boolean","description":"Default true."},"idempotency_key":{"type":"string"},"live":{},"max_credits":{"type":"number","exclusiveMinimum":0},"max_records_per_filter":{"type":"integer","minimum":1,"maximum":5000},"mode":{"type":"string","enum":["dry_run","live"]},"org_dnc_filter_id":{"type":"string"},"org_domain_field":{"type":"string","description":"Website/domain field key; never inferred from email."},"org_linkedin_field":{"type":"string"},"personFields":{},"person_fields":{"type":"array","items":{"type":"string"},"maxItems":15},"person_linkedin_field":{"type":"string","description":"Field key holding a LinkedIn URL."},"person_title_field":{"type":"string","description":"Pipedrive has no native title; map a field."},"project":{"type":"string"},"refresh":{"type":"string","enum":["once","scheduled"],"description":"Defaults to scheduled."},"reviewed_fingerprint":{"type":"string"},"table_name":{"type":"string"},"timezone":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_pipedrive_import"]}},"/api/cli/tables/preview":{"post":{"operationId":"postTablesPreview","tags":["Tables"],"summary":"Preview Table","description":"Rows, columns, stats, and a deep-link; 0 credits. UI in MCP Apps hosts; data in terminals. Fill exact to cap, else summary.statsSampled; rowCount exact.\n\nMCP: `oxygen_tables_preview`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","description":"Column keys or ids to include.","items":{"type":"string","minLength":1,"maxLength":200},"minItems":1,"maxItems":100},"include_cell_states":{"type":"boolean","description":"Include compact per-cell run state (default false)."},"include_system_fields":{"type":"boolean","description":"Include _row_id, _created_at, _updated_at (default false)."},"summary_only":{"type":"boolean","description":"Metadata and whole-table fill stats, no row JSON. fillRate = non-null; nonEmptyRate also drops blanks."},"table":{"type":"string","description":"ID, slug, or Table URL.","minLength":1,"maxLength":400}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_preview"]}},"/api/cli/tables/promote":{"post":{"operationId":"postTablesPromote","tags":["Tables"],"summary":"Promote Rows to Records","description":"Writes bound rows' columns onto their CRM records. Truth write: dry_run previews; approved=true writes.\n\nMCP: `oxygen_tables_promote`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Confirm the write."},"dryRun":{},"dry_run":{"type":"boolean","description":"Preview only."},"map":{},"mappings":{"type":"array","description":"Column-to-attribute maps.","items":{"type":"object","properties":{"column":{"type":"string","description":"Source column key."},"attribute":{"type":"string","description":"Target attribute slug."}},"required":["column","attribute"]},"minItems":1},"max_concurrency":{"type":"integer","description":"Max concurrent items.","minimum":1,"maximum":4000},"object":{"type":"string","description":"CRM object slug; inferred from a single bind column."},"policy":{"type":"string","description":"Policy.","enum":["fill_empty_only","overwrite","skip_conflicts"]},"rowIds":{},"row_ids":{"type":"array","description":"Row ids; default: all bound rows.","items":{"type":"string"}},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_promote"]}},"/api/cli/tables/query":{"post":{"operationId":"postTablesQuery","tags":["Tables"],"summary":"Query Table Rows","description":"Raw rows or grid previews. Grid rejects raw selectors; nextCursor pages. Full cells: oxygen_table_row_inspect projection=value.\n\nMCP: `oxygen_table_ingestions_wait`, `oxygen_table_runs_wait`, `oxygen_tables_preview`, `oxygen_tables_query`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"cursor":{"type":"string","description":"Opaque cursor."},"fields":{"type":"array","description":"Column keys/ids.","items":{"type":"string","minLength":1,"maxLength":200},"minItems":1,"maxItems":100},"filter":{"type":"object","description":"Legacy filter.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","contains","not_contains","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"filterTree":{"type":"object","description":"{type:'group',conjunction:'and'|'or',children:[{type:'leaf',columnKey,operator,value?}]}; native operators."},"filter_tree":{},"filters":{"type":"array","description":"AND; not with filterTree/sorts.","items":{"type":"object","description":"Row filter, e.g. {column:'email', op:'is_null'}.","properties":{"column":{"type":"string","minLength":1,"maxLength":200},"op":{"type":"string","enum":["is_null","is_not_null","eq","neq","contains","not_contains","in","not_in"]},"value":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}},{"type":"object","additionalProperties":true}]}},"required":["column","op"]},"minItems":1,"maxItems":20},"format":{"type":"string","enum":["grid"],"description":"Grid cell previews."},"formulaValues":{},"formula_values":{"type":"string","enum":["materialized"],"description":"Force-rerun first (0 credits)."},"includeSystemFields":{},"include_fill":{"type":"boolean","description":"Empty first-page fill state."},"include_stats":{"type":"boolean","description":"Optional column stats."},"include_system_fields":{"type":"boolean","description":"System fields (default true)."},"limit":{"type":"integer","description":"Raw default 100, grid 50; MCP clamps explicit limits to 100.","minimum":1,"maximum":500},"max_chars":{"type":"integer","minimum":1000,"maximum":100000,"description":"External result window; built-in hosts cap."},"offset":{"type":"integer","minimum":0,"description":"Row offset; alternative to cursor."},"rowId":{},"row_id":{"type":"string","description":"One row; ignores limit/cursor."},"search":{"type":"string","description":"AND text across searchable columns."},"search_text":{},"slug":{},"sort":{},"sorts":{"type":"array","description":"Priority order; _row_id breaks ties.","items":{"type":"object","properties":{"columnKey":{"type":"string","minLength":1,"maxLength":200},"direction":{"type":"string","enum":["asc","desc"],"description":"Default asc."},"path":{"type":"string","maxLength":200},"valueOrder":{"description":"Custom label order (value_order alias): up to 64 ASCII labels, 1–64 chars; alphanumeric first, then alphanumeric/space/_-./&. Trim/lowercase; first duplicate wins. Asc: listed first, unlisted/null last; desc reverses. []: ordinary sort; null falls back to alias."}},"required":["columnKey"]},"maxItems":16},"table":{"type":"string","description":"Table id, slug or URL.","minLength":1,"maxLength":400},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_ingestions_wait","oxygen_table_runs_wait","oxygen_tables_preview","oxygen_tables_query"]}},"/api/cli/tables/records-import":{"post":{"operationId":"postTablesRecordsImport","tags":["Tables"],"summary":"Import Records into a Table","description":"Copy a Records object or saved view into a new Table, keyed by record id, once or kept in sync. The copy is free; each scheduled sync bills one workflow step. Records stay unchanged. dry_run previews.\n\nMCP: `oxygen_tables_records_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Approve the standing per-sync charge (credits_per_scheduled_sync) that refresh=sync arms."},"dry_run":{"type":"boolean","description":"Preview counts without writing."},"every":{"type":"string","description":"With refresh=sync: hourly, every_6h, daily@<hour> or weekly@<day><hour>, UTC. Default daily@6."},"name":{"type":"string","description":"New Table name."},"object":{"type":"string","description":"Records object slug, e.g. companies, people, deals."},"project":{"type":"string","description":"Project id or slug."},"refresh":{"type":"string","enum":["once","sync"],"description":"once (default) copies now; sync also refreshes on a schedule and needs approved."},"view":{"type":"string","description":"Saved view id or exact name on that object. Omit for every record."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_records_import"]}},"/api/cli/tables/records-sync":{"get":{"operationId":"getTablesRecordsSync","tags":["Tables"],"summary":"Records Table Sync Status","description":"Read a Records-imported Table's source object and view, last sync counts and schedule. Free.\n\nMCP: `oxygen_tables_records_status`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"Table id, slug or URL.","minLength":1,"maxLength":400}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_records_status"]},"post":{"operationId":"postTablesRecordsSync","tags":["Tables"],"summary":"Sync a Records Table","description":"Copy a Records-imported Table's source again now: adds new records, updates changed cells, keeps edited cells (preserved_cells counts those copied-field cells; added columns are never touched), marks departed records in_records=false. Free now; scheduled syncs bill one workflow step each.\n\nMCP: `oxygen_tables_records_sync`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Approve the standing per-sync charge (credits_per_scheduled_sync) that refresh=sync arms."},"dry_run":{"type":"boolean","description":"Preview counts without writing."},"every":{"type":"string","description":"With refresh=sync: hourly, every_6h, daily@<hour> or weekly@<day><hour>, UTC. Default daily@6."},"refresh":{"type":"string","enum":["once","sync"],"description":"Omit to keep the schedule; sync (approved) arms or retimes it; once removes it."},"table":{"type":"string","description":"Table id, slug or URL.","minLength":1,"maxLength":400}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_records_sync"]}},"/api/cli/tables/recover-pending":{"post":{"operationId":"tables.recover_pending","tags":["Tables"],"summary":"Tables recover pending","description":"Recover BetterContact email/phone requests and read verification blockers; no new orders or imports.\n\nMCP: `oxygen_tables_recover_pending`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table":{"type":"string","minLength":1,"description":"Table id or slug."},"max_items":{"type":"integer","minimum":1,"maximum":1000,"description":"Pending requests to poll; default 1000."}},"required":["table"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_recover_pending"]}},"/api/cli/tables/relations":{"get":{"operationId":"getTablesRelations","tags":["Tables"],"summary":"Manage Table Relations","description":"Table relation definitions: list is read-only; update changes display_name, inverse_display_name, or source-perspective cardinality, keeping endpoints/slugs. archive hides both columns and active edges, preserving history. update/archive preview by default; approved=true applies reviewed changes.\n\nMCP: `oxygen_tables_relations`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},{"name":"tableId","in":"query","required":false,"schema":{}},{"name":"table_id","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_relations"]},"post":{"operationId":"postTablesRelations","tags":["Tables"],"summary":"Relate Tables","description":"Links two tables (web: Link to another table): a linked-record column on BOTH, empty until rows link; no matching values needed; plain tables are never registered as CRM objects. A standard CRM object target gets no inverse column (two_sided false). Cardinality source:target, default many_to_many; one_to_many: each source row links many target rows, each target row one source; a 'one' side archives the prior link. Then oxygen_tables_link, or oxygen_tables_link_bulk by value. Free; dry_run until mode='live'.\n\nMCP: `oxygen_tables_relate`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["dry_run","live"]},"relationship":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_relate"]},"patch":{"operationId":"patchTablesRelations","tags":["Tables"],"summary":"Manage Table Relations","description":"Table relation definitions: list is read-only; update changes display_name, inverse_display_name, or source-perspective cardinality, keeping endpoints/slugs. archive hides both columns and active edges, preserving history. update/archive preview by default; approved=true applies reviewed changes.\n\nMCP: `oxygen_tables_relations`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"cardinality":{"type":"string","description":"Source-perspective cardinality (update only).","enum":["one_to_one","one_to_many","many_to_one","many_to_many"]},"displayName":{},"display_name":{"type":"string","description":"New label on this table (update only).","maxLength":200},"inverseDisplayName":{},"inverse_display_name":{"type":"string","description":"New label on the other table (update only).","maxLength":200},"mode":{},"relation":{"type":"string","description":"Relation slug as seen from this table. Required for update/archive.","minLength":1,"maxLength":120},"relationship":{},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_relations"]},"delete":{"operationId":"deleteTablesRelations","tags":["Tables"],"summary":"Manage Table Relations","description":"Table relation definitions: list is read-only; update changes display_name, inverse_display_name, or source-perspective cardinality, keeping endpoints/slugs. archive hides both columns and active edges, preserving history. update/archive preview by default; approved=true applies reviewed changes.\n\nMCP: `oxygen_tables_relations`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"cardinality","in":"query","required":false,"schema":{"type":"string","description":"Source-perspective cardinality (update only).","enum":["one_to_one","one_to_many","many_to_one","many_to_many"]}},{"name":"display_name","in":"query","required":false,"schema":{"type":"string","description":"New label on this table (update only).","maxLength":200}},{"name":"inverse_display_name","in":"query","required":false,"schema":{"type":"string","description":"New label on the other table (update only).","maxLength":200}},{"name":"mode","in":"query","required":false,"schema":{}},{"name":"relation","in":"query","required":false,"schema":{"type":"string","description":"Relation slug as seen from this table. Required for update/archive.","minLength":1,"maxLength":120}},{"name":"relationship","in":"query","required":false,"schema":{}},{"name":"slug","in":"query","required":false,"schema":{}},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},{"name":"tableId","in":"query","required":false,"schema":{}},{"name":"table_id","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_relations"]}},"/api/cli/tables/relations/link":{"post":{"operationId":"postTablesRelationsLink","tags":["Tables"],"summary":"Link Table Rows","description":"Links one row to a row in the related table through a relation defined with oxygen_tables_relate. Links live in the edge store with provenance and archive history (not in the row); a 'one' cardinality side archives the previous link. Free internal write. Defaults to dry_run; pass mode='live' or live=true after inspecting the preview.\n\nMCP: `oxygen_tables_link`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","description":"Defaults to dry_run; use live only after inspecting the preview.","enum":["dry_run","live"]},"relation":{"type":"string","description":"Relation slug defined on the source table, such as client.","minLength":1,"maxLength":120},"relationship":{},"rowId":{},"row_id":{"type":"string","description":"Source row id.","minLength":1,"maxLength":120},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{},"targetRowId":{},"target_row_id":{"type":"string","description":"Row id in the related table; oxygen_tables_query search finds it.","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_link"]}},"/api/cli/tables/relations/unlink":{"post":{"operationId":"postTablesRelationsUnlink","tags":["Tables"],"summary":"Unlink Table Rows","description":"Unlinks one exact source/target row pair by archiving its edge. The relation definition and endpoint rows remain, and a later link can reconnect them. Free internal write. Defaults to dry_run; pass approved=true only after inspecting the preview.\n\nMCP: `oxygen_tables_unlink`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{},"relation":{"type":"string","description":"Relation slug as seen from the source table.","minLength":1,"maxLength":120},"relationship":{},"rowId":{},"row_id":{"type":"string","description":"Source row id.","minLength":1,"maxLength":120},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{},"targetRowId":{},"target_row_id":{"type":"string","description":"Linked target row id to remove.","minLength":1,"maxLength":120}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_unlink"]}},"/api/cli/tables/rename":{"post":{"operationId":"postTablesRename","tags":["Tables"],"summary":"Rename Table","description":"Renames an existing workspace table.\n\nMCP: `oxygen_tables_rename`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New table name.","minLength":1,"maxLength":200},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_rename"]}},"/api/cli/tables/restore":{"post":{"operationId":"postTablesRestore","tags":["Tables"],"summary":"Restore Table","description":"Restores table and folder, cancels a purge that has not begun, and reclaims its slug when available.\n\nMCP: `oxygen_tables_restore`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"table_id":{},"tables":{"type":"array","minItems":1,"items":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"description":"Batch of exact tables; alternative to table."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_restore"]}},"/api/cli/tables/rows":{"post":{"operationId":"postTablesRows","tags":["Tables"],"summary":"Insert Rows","description":"Appends <=500 rows without value dedup. Reuse request_id after a timeout; payload changes are rejected. Use oxygen_rows_upsert for value dedup.\n\nMCP: `oxygen_rows_insert`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{},"request_id":{"type":"string","minLength":1,"maxLength":200,"description":"Stable timeout-retry key."},"rows":{"type":"array","description":"Rows by column key; <=500 rows and <=2 MB/call. Split wide rows; local files: oxygen_cli_file_import_prepare.","items":{"type":"object","additionalProperties":true},"minItems":1,"maxItems":500},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_rows_insert"]}},"/api/cli/tables/rows/delete":{"post":{"operationId":"postTablesRowsDelete","tags":["Tables"],"summary":"Delete Rows","description":"Deletes exact row IDs; by filter: oxygen_table_rows_remove_selection filter_tree. Permanent; get user approval first, then execute immediately. Returns count, missing IDs, web_url and campaign warnings.\n\nMCP: `oxygen_rows_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"metadata":{"type":"object","additionalProperties":true,"description":"Durable row change provenance."},"rowId":{},"rowIds":{},"row_id":{"type":"string","description":"Single row id to delete.","minLength":1},"row_ids":{"type":"array","description":"Batch of row ids to delete.","items":{"type":"string","minLength":1},"minItems":1,"maxItems":500},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_rows_delete"]}},"/api/cli/tables/rows/history":{"post":{"operationId":"postTablesRowsHistory","tags":["Tables"],"summary":"Row Change History","description":"Returns the cell-change provenance of one row across all its columns for the last 30 days — who/what wrote each value (api/cli/tool/workflow/system, with run ids and statuses), old → new values, and timestamps — plus webhook row provenance when the row was written by a table webhook. The value-history complement to oxygen_runs_get: use it to answer 'where did this value come from?' or 'what changed on this lead?'.\n\nMCP: `oxygen_rows_history`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"type":"number","description":"Max change rows to return (default 50).","minimum":1,"maximum":200},"rowId":{},"row_id":{"type":"string","description":"Workspace row id (UUID).","minLength":1,"maxLength":64},"table":{"type":"string","description":"Workspace table id or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_rows_history"]}},"/api/cli/tables/rows/update":{"post":{"operationId":"postTablesRowsUpdate","tags":["Tables"],"summary":"Update Row","description":"Updates the values of a single row by id.\n\nMCP: `oxygen_rows_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"metadata":{"type":"object","additionalProperties":true,"description":"Durable row change provenance."},"rowId":{},"row_id":{"type":"string","description":"Row id to update.","minLength":1},"slug":{},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tableId":{},"table_id":{},"values":{"type":"object","description":"Column-keyed values to overwrite.","additionalProperties":true}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_rows_update"]}},"/api/cli/tables/rows/upsert":{"post":{"operationId":"postTablesRowsUpsert","tags":["Tables"],"summary":"Upsert Rows","description":"Inserts or updates a batch, deduplicating on the key column. dry_run=true first on messy lists; local files use oxygen_cli_file_import_prepare.\n\nMCP: `oxygen_rows_upsert`, `oxygen_tools_plan_table_batch`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"dry_run":{"type":"boolean","description":"Previews inserts, updates, duplicates, and conflicts without writing."},"key":{"type":"string","description":"Column key to deduplicate on.","minLength":1},"request_id":{},"return":{"type":"string","description":"summary: counts; ids: adds row ids; rows: full values.","enum":["summary","ids","rows"]},"rows":{"type":"array","description":"Rows keyed by column key. Keep <=500 rows and <=2 MB JSON per call (split wide rows); local files use oxygen_cli_file_import_prepare.","items":{"type":"object","additionalProperties":true},"minItems":1,"maxItems":500},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_rows_upsert","oxygen_tools_plan_table_batch"]}},"/api/cli/tables/schedule":{"get":{"operationId":"getTablesSchedule","tags":["Tables"],"summary":"Scheduled Column Refresh","description":"Scheduled column refresh (create/list/remove): a cron workflow re-runs one column — empty/failed cells only unless force. One schedule per column; create replaces; remove cancels its queued, unstarted runs. Paid kinds (tool/ai/enrichment) require max_credits + approved; formula is free.\n\nMCP: `oxygen_tables_schedule`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_schedule"]},"post":{"operationId":"postTablesSchedule","tags":["Tables"],"summary":"Scheduled Column Refresh","description":"Scheduled column refresh (create/list/remove): a cron workflow re-runs one column — empty/failed cells only unless force. One schedule per column; create replaces; remove cancels its queued, unstarted runs. Paid kinds (tool/ai/enrichment) require max_credits + approved; formula is free.\n\nMCP: `oxygen_tables_schedule`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"create: approve the recurring paid runs."},"column":{"type":"string","description":"create/remove: column key or id."},"cron":{"type":"string","description":"create: cron expression in UTC, e.g. \"0 9 * * *\"."},"every":{"type":"string","description":"create: hourly, every_6h, daily@<hour>, or weekly@<day><hour> (UTC)."},"force":{"type":"boolean","description":"create: re-run populated cells every tick."},"max_credits":{"type":"number","description":"create: credit ceiling per refresh.","exclusiveMinimum":0},"pacing":{"type":"string","enum":["deadline","immediate"],"description":"create: deadline (default) queues each run to finish by its deadline; immediate starts it when the schedule fires."},"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_schedule"]},"delete":{"operationId":"deleteTablesSchedule","tags":["Tables"],"summary":"Scheduled Column Refresh","description":"Scheduled column refresh (create/list/remove): a cron workflow re-runs one column — empty/failed cells only unless force. One schedule per column; create replaces; remove cancels its queued, unstarted runs. Paid kinds (tool/ai/enrichment) require max_credits + approved; formula is free.\n\nMCP: `oxygen_tables_schedule`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"column","in":"query","required":false,"schema":{"type":"string","description":"create/remove: column key or id."}},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_schedule"]}},"/api/cli/tables/send":{"post":{"operationId":"postTablesSend","tags":["Tables"],"summary":"Send Rows to Another Table","description":"Copies rows between tables, or flattens a JSON array cell into one row per element, as a durable run (free). Map columns explicitly or automap (echoed as resolved_mapping). dry_run previews without writing.\n\nMCP: `oxygen_tables_send`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"automap":{"type":"boolean","description":"Resolve the mapping when mapping is omitted."},"dry_run":{"type":"boolean","description":"Validate + preview only; writes nothing."},"filter":{},"filters":{"type":"array","description":"Source-row predicates {column, op, value?}; op eq|neq|is_null|is_not_null|in|not_in.","items":{"type":"object","additionalProperties":true}},"flatten":{"type":"object","description":"Emit one row per element when this column's (path-resolved) value is an array; non-arrays pass through once.","properties":{"column":{"type":"string","description":"Source column key."},"path":{"type":"string","description":"Dot-path to the array."}},"required":["column"],"additionalProperties":false},"mapping":{"type":"array","description":"Entries {target, source:{type:'column',key}|{type:'literal',value}, path?}; path digs into JSON values. With flatten, source key '$element' is the element.","items":{"type":"object","properties":{"target":{"type":"string","description":"Target column key (manual/source kinds)."},"source":{"type":"object","description":"{type:'column',key} or {type:'literal',value}."},"path":{"type":"string","description":"Dot-path into the source value."}},"required":["target","source"],"additionalProperties":true},"minItems":1},"mode":{"type":"string","description":"Write mode.","enum":["insert","upsert"]},"page_size":{"type":"integer","description":"Rows per durable page. Default 500.","minimum":1,"maximum":2000},"source":{"type":"string","description":"Source table id or slug.","minLength":1},"target":{"type":"string","description":"Target table id or slug (must differ).","minLength":1},"upsert_key":{"type":"string","description":"Mapped target column identifying existing rows."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tables_send"]}},"/api/cli/tables/sources":{"get":{"operationId":"getTablesSources","tags":["Tables"],"summary":"Table Sources","description":"Lists every way a table can start — imports, company/people/signal sources, webhooks, functions — with the provider count and per-row credit estimate behind each, derived from the routing registry. Free: nothing is called or written.\n\nMCP: `oxygen_tables_sources`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"group","in":"query","required":false,"schema":{"type":"string","enum":["Companies","People","Professional Network","Imports","CRM","Signals","Tables"],"description":"One group only."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_sources"]}},"/api/cli/tables/tags":{"post":{"operationId":"postTablesTags","tags":["Tables"],"summary":"Tag Table","description":"Replaces a table's workspace tags (whole-set; [] clears). Tags link the table to sequences, wiki pages, and workflows carrying the same tag — browse with oxygen_tags_get.\n\nMCP: `oxygen_tables_tag`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"table":{"type":"string","description":"ID or slug.","minLength":1,"maxLength":200},"tags":{"type":"array","items":{"type":"string"},"maxItems":50,"description":"The table's new tag set."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_tag"]}},"/api/cli/tables/tidy/suggest":{"post":{"operationId":"postTablesTidySuggest","tags":["Tables"],"summary":"Suggest Table Tidy","description":"Read-only tidy analysis of one Oxygen table. Samples up to 5000 rows and reports likely-duplicate columns, formatting inconsistencies (mixed casing, stray whitespace, mixed number/date formats, type mismatches), columns worth hiding (low fill, all-identical, or near-empty), and value-sanity findings. Makes no changes and consumes no credits. Apply approved scoped fixes with oxygen_columns_update (hidden_by_default for visibility), oxygen_columns_reorder or oxygen_columns_archive; read back with oxygen_tables_describe. The response includes an oxygen-agent.com deep-link to the table.\n\nMCP: `oxygen_tables_tidy_suggest`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"categories":{"type":"array","description":"Tidy checks to run. Omit or leave empty to run all four.","items":{"type":"string","enum":["duplicates","formatting","hide","valueSanity"]},"minItems":1,"maxItems":4},"limit":{"type":"integer","description":"Rows to sample. Defaults to and is capped at 5000.","minimum":1,"maximum":5000},"table":{"type":"string","description":"ID, slug, or Table URL.","minLength":1,"maxLength":400}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tables_tidy_suggest"]}},"/api/cli/tables/views":{"get":{"operationId":"getTablesViews","tags":["Tables"],"summary":"Get Table View","description":"Returns a single saved view (name, type, default flag, full config) by id.\n\nMCP: `oxygen_tables_views_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tables_views_get"]}},"/api/cli/tables/webhooks":{"get":{"operationId":"getTablesWebhooks","tags":["Tables"],"summary":"List Table Webhooks","description":"Lists the organization's direct table webhook endpoints, optionally filtered by table or status, each with its webhook URL, table deep-link and standing auto-run columns, plus rate_limit (deliveries a minute on this plan). Read-only; Create/edit with oxygen_table_webhook_create/update; auth_mode=secret rotates the secret.\n\nMCP: `oxygen_table_webhook_get`, `oxygen_table_webhooks_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"endpointId","in":"query","required":false,"schema":{}},{"name":"endpoint_id","in":"query","required":false,"schema":{}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum endpoints to return (1-500). Defaults to 100.","minimum":1,"maximum":500}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by endpoint status.","enum":["active","disabled"]}},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"Table id, slug, or copied Oxygen table URL. Filters to one table.","minLength":1,"maxLength":400}},{"name":"webhook","in":"query","required":false,"schema":{}},{"name":"webhookId","in":"query","required":false,"schema":{}},{"name":"webhook_id","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_webhook_get","oxygen_table_webhooks_list"]},"post":{"operationId":"tables.webhooks.create","tags":["Tables"],"summary":"Tables webhook create","description":"Create an inbound Table webhook or platform LinkedIn feed. Optional auto_run is standing permission with explicit or plan-default delivery ceilings.\n\nMCP: `oxygen_table_webhook_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table":{"type":"string"},"name":{"type":"string"},"mode":{"type":"string","enum":["insert","upsert"]},"upsert_key":{"type":"string"},"items_path":{"type":"string"},"event_id_path":{"type":"string"},"event_type_path":{"type":"string"},"occurred_at_path":{"type":"string"},"auth_mode":{"type":"string","enum":["none","secret"]},"feed_kind":{"type":"string","enum":["generic","unipile"]},"unipile_account_id":{"type":"string"},"event_types":{"type":"array","items":{"type":"string"}},"mapping":{"type":"string"},"auto_run":{"type":"object","additionalProperties":true}},"required":["table"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_webhook_create"]},"patch":{"operationId":"tables.webhooks.update","tags":["Tables"],"summary":"Tables webhook update","description":"Edit a Table webhook's name, state or standing auto_run; auth_mode=secret rotates its secret and returns it once.\n\nMCP: `oxygen_table_webhook_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"endpoint_id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["active","disabled"]},"auth_mode":{"type":"string","enum":["none","secret"]},"auto_run":{"type":"object","additionalProperties":true},"clear_auto_run":{"type":"boolean"}},"required":["endpoint_id"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_table_webhook_update"]}},"/api/cli/tables/webhooks/deliveries":{"get":{"operationId":"getTablesWebhooksDeliveries","tags":["Tables"],"summary":"List Table Webhook Deliveries","description":"Lists direct table webhook deliveries and their auto-run enqueue status for the active organization. Filter by table, endpoint id, delivery status (received/completed/failed), or auto-run status (not_configured/queued/skipped/failed_to_enqueue). Each delivery includes the target table, rows written, the run it kicked off, and an observability deep-link. Read-only.\n\nMCP: `oxygen_table_webhook_deliveries`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"autoRunStatus","in":"query","required":false,"schema":{}},{"name":"auto_run_status","in":"query","required":false,"schema":{"type":"string","description":"Filter by webhook auto-run enqueue status.","enum":["not_configured","queued","skipped","failed_to_enqueue"]}},{"name":"endpointId","in":"query","required":false,"schema":{}},{"name":"endpoint_id","in":"query","required":false,"schema":{"type":"string","description":"Webhook endpoint id, such as tw_....","minLength":1,"maxLength":200}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum deliveries to return (1-200). Defaults to 50.","minimum":1,"maximum":200}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter by delivery status.","enum":["received","completed","failed"]}},{"name":"table","in":"query","required":false,"schema":{"type":"string","description":"Table id, slug, or copied Oxygen table URL. Filters to one table.","minLength":1,"maxLength":400}},{"name":"webhook","in":"query","required":false,"schema":{}},{"name":"webhookId","in":"query","required":false,"schema":{}},{"name":"webhook_id","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_table_webhook_deliveries"]}},"/api/cli/tags":{"get":{"operationId":"getTags","tags":["Tags"],"summary":"List Workspace Tags","description":"Lists every workspace tag with per-kind counts across publishing posts, knowledge pages, sequences, tables, workflows, recipes, inbox conversations, CRM records, mailboxes, sender accounts, sending domains, projects, sender profiles, phone numbers, signal types, dashboards, agents, and saved Ads searches.\n\nMCP: `oxygen_tags_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tags_list"]}},"/api/cli/tags/{tag}":{"get":{"operationId":"getTagsTag","tags":["Tags"],"summary":"Get Tagged Items","description":"Everything carrying one workspace tag across publishing posts, knowledge pages, sequences, tables, workflows, recipes, inbox conversations, CRM records, mailboxes, sender accounts, sending domains, projects, sender profiles, phone numbers, signal types, dashboards, agents, and saved Ads searches — each item with name, status, and deep-link.\n\nMCP: `oxygen_tags_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tag","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tags_get"]},"post":{"operationId":"postTagsTag","tags":["Tags"],"summary":"Declare or Annotate a Tag","description":"Declares a workspace tag before anything carries it, or annotates one already in use, with a description, pill color, and pinned flag. Idempotent upsert — `created` reports which happened. Never touches carriers: declaring is annotation, not attachment. Omit a field to leave it unchanged; use the matching clear_* flag to remove a value.\n\nMCP: `oxygen_tags_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tag","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"color":{"type":"string","enum":["gray","red","orange","amber","yellow","green","teal","blue","indigo","purple","pink"],"description":"Pill color. Omit to keep deriving it from the label."},"description":{"type":"string","description":"What the tag means in this workspace."},"pinned":{"type":"boolean","description":"Pin the tag to the top of the tag list and the tag picker."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tags_set"]}},"/api/cli/tags/bulk":{"get":{"operationId":"getTagsBulk","tags":["Tags"],"summary":"Get Tagged Items","description":"Everything carrying one workspace tag across publishing posts, knowledge pages, sequences, tables, workflows, recipes, inbox conversations, CRM records, mailboxes, sender accounts, sending domains, projects, sender profiles, phone numbers, signal types, dashboards, agents, and saved Ads searches — each item with name, status, and deep-link.\n\nMCP: `oxygen_tags_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tags_get"]},"post":{"operationId":"postTagsBulk","tags":["Tags"],"summary":"Merge or Delete Workspace Tags","description":"Merges several workspace tags into one, or deletes them outright. Preview-first: without apply=true, returns per-kind and per-tag would-change counts and mutates nothing. DELETE IS IRREVERSIBLE — it strips the tag from every carrier, INCLUDING archived and finished items the tag index hides, and removes its declaration. Counts therefore routinely exceed what oxygen_tags_list shows. Idempotent — safe to re-run after a partial failure.\n\nMCP: `oxygen_tags_bulk`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["merge","delete"],"description":"merge = fold `tags` into `into`; delete = remove `tags` everywhere."},"apply":{"type":"boolean","description":"Execute it. Omit/false = preview counts only."},"approved":{},"into":{"type":"string","minLength":1,"maxLength":200,"description":"merge only: the surviving tag. Rejected for delete."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":200},"minItems":1,"maxItems":50,"description":"The tags to merge away, or to delete."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_tags_bulk"]}},"/api/cli/tags/rename":{"get":{"operationId":"getTagsRename","tags":["Tags"],"summary":"Get Tagged Items","description":"Everything carrying one workspace tag across publishing posts, knowledge pages, sequences, tables, workflows, recipes, inbox conversations, CRM records, mailboxes, sender accounts, sending domains, projects, sender profiles, phone numbers, signal types, dashboards, agents, and saved Ads searches — each item with name, status, and deep-link.\n\nMCP: `oxygen_tags_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tags_get"]},"post":{"operationId":"postTagsRename","tags":["Tags"],"summary":"Rename Workspace Tag","description":"Renames one workspace tag everywhere it appears (archived rows included). Preview-first: without apply=true, returns per-kind would-change counts and mutates nothing. Idempotent — safe to re-run.\n\nMCP: `oxygen_tags_rename`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"apply":{"type":"boolean","description":"Execute the rename. Omit/false = preview counts only."},"from":{"type":"string","description":"The current tag (case-insensitive)."},"to":{"type":"string","description":"The new tag (case preserved; matching ignores case)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tags_rename"]}},"/api/cli/teammates":{"get":{"operationId":"teammates.list","tags":["Teammates"],"summary":"Oxygents list","description":"List the Oxygents you can use, the first one (is_default) on top: name, what each does, its look, what you are to it (access: owner, manager or collaborator) and your chat with each (working or waiting for you, unread, its latest words). Pinned ones follow the first; hidden ones are marked. Use chat.session_id with copilot history (oxygen_copilot_history) to search past messages and recorded links.\n\nCLI: `oxygen oxygents list`.\n\nMCP: `oxygen_oxygents_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_oxygents_list"],"x-oxygen-cli-command":"oxygen oxygents list"},"post":{"operationId":"teammates.create","tags":["Teammates"],"summary":"Oxygents create","description":"Add an Oxygent to the workspace, named \"New Bot\" unless you name it; tell it its job in your chat with it. It can chat at once and run on its own (background tasks, routines), reading freely and asking before anything that writes, sends or spends. You own it. Workspace access as collaborators and a shared chat are the default; choose personal for creator-only access. Free: adding one starts no inference.\n\nCLI: `oxygen oxygents create`.\n\nMCP: `oxygen_oxygents_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"What everyone calls it."},"description":{"type":"string","maxLength":500,"description":"The job it does, in a sentence or two; other Oxygents hand it work by it. Empty clears it."},"avatar_key":{"type":"string","enum":["o2","atom","twin","tripod","mark","clover","trio","bubbles","crown","orbit","comet","pill"],"description":"The shape of its face."},"avatar_color":{"type":"string","enum":["forest","brown","red","orange","amber","green","aqua","blue","violet","purple","magenta","slate"],"description":"The colour of its face."},"visibility":{"type":"string","enum":["workspace","personal"],"description":"Workspace (default) shares one chat history with everyone who has access. Personal is accessible only to its creator here, including against workspace admins. Explicitly saving to team memory publishes that entry to the workspace. An API key acts as the person who issued it."},"template":{"type":"string","enum":["reply"],"description":"Dev Reply Oxygent: learn sender voice and prepare approval-required batches."},"slug":{"type":"string","minLength":2,"maxLength":49,"pattern":"^[a-z][a-z0-9-]{1,48}$","description":"Its permanent handle in commands and links; made from the name when omitted."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_create"],"x-oxygen-cli-command":"oxygen oxygents create"}},"/api/cli/teammates/{slug}":{"get":{"operationId":"teammates.get","tags":["Teammates"],"summary":"Oxygents get","description":"Read one Oxygent's profile, chat metadata and visibility. Use chat.session_id with copilot history (oxygen_copilot_history) to search past messages and recorded links.\n\nCLI: `oxygen oxygents get`.\n\nMCP: `oxygen_oxygents_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_oxygents_get"],"x-oxygen-cli-command":"oxygen oxygents get"},"patch":{"operationId":"teammates.update","tags":["Teammates"],"summary":"Oxygents update","description":"Edit an Oxygent's profile, or change visibility as its owner with confirm_visibility. Owners, managers and workspace admins can edit profiles. History is kept in both directions: Workspace shares it all; Personal removes others' future access but cannot retract what they saw. Home (the first Oxygent) stays Workspace. Free.\n\nCLI: `oxygen oxygents update`.\n\nMCP: `oxygen_oxygents_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"What everyone calls it."},"description":{"type":"string","maxLength":500,"description":"The job it does, in a sentence or two; other Oxygents hand it work by it. Empty clears it."},"avatar_key":{"type":"string","enum":["o2","atom","twin","tripod","mark","clover","trio","bubbles","crown","orbit","comet","pill"],"description":"The shape of its face."},"avatar_color":{"type":"string","enum":["forest","brown","red","orange","amber","green","aqua","blue","violet","purple","magenta","slate"],"description":"The colour of its face."},"visibility":{"type":"string","enum":["workspace","personal"],"description":"Only the owner can change visibility. Workspace grants everyone collaborator access and shares the complete history; Personal retains all messages, removes additional grants and everyone else's future access. Explicitly saving to team memory publishes that entry to the workspace. Home (the first Oxygent) stays Workspace."},"confirm_visibility":{"type":"boolean","description":"Required when changing visibility: publishing shares all history; making personal removes everyone else's future access but cannot retract what they saw."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_update"],"x-oxygen-cli-command":"oxygen oxygents update"}},"/api/cli/teammates/{slug}/access":{"get":{"operationId":"teammates.access","tags":["Teammates"],"summary":"Oxygents access","description":"Read access (visibility, owner, everyone, named people with roles, fixed and your permissions), without chat history. A collaborator uses its shared chat; a manager also changes its profile and access. Personal is creator-only; Home (the first Oxygent) is fixed. Free.\n\nCLI: `oxygen oxygents access`.\n\nMCP: `oxygen_oxygents_access`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_oxygents_access"],"x-oxygen-cli-command":"oxygen oxygents access"},"post":{"operationId":"teammates.share","tags":["Teammates"],"summary":"Oxygents share","description":"Share an Oxygent with teammates, or stop sharing it: with everyone in the workspace (everyone), or with people by their workspace email (add, as role; remove). Everyone with access reads the same chat history. Personal Oxygents cannot be shared; change visibility explicitly first. Its owner, its managers or a workspace admin only; never the first Oxygent, which is everyone's. Free.\n\nCLI: `oxygen oxygents share`.\n\nMCP: `oxygen_oxygents_share`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"everyone":{"type":"string","enum":["collaborator","manager","off"],"description":"Workspace-wide role: collaborator (the default), manager, or off (owner and named people, with workspace admins retaining management access). This restricts a Workspace Oxygent's audience; it does not make it Personal or split its shared chat."},"add":{"type":"array","items":{"type":"string","minLength":3,"maxLength":320},"maxItems":50,"description":"People to share it with, by their workspace email."},"role":{"type":"string","enum":["collaborator","manager"],"description":"What the people in add become: collaborator (the default), who uses the same shared chat, or manager, who also changes its profile and access. Adding someone already listed changes their role."},"remove":{"type":"array","items":{"type":"string","minLength":3,"maxLength":320},"maxItems":50,"description":"Remove named grants by workspace email or the user_id access lists for former members. All messages stay in the shared history. Workspace-wide access still applies; use everyone off to remove that grant too."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_share"],"x-oxygen-cli-command":"oxygen oxygents share"}},"/api/cli/teammates/{slug}/activity":{"get":{"operationId":"teammates.activity","tags":["Teammates"],"summary":"Oxygents activity","description":"List an Oxygent's recent work: its runs and the actions taken in its chats, as metadata only (no goals or messages).\n\nCLI: `oxygen oxygents activity`.\n\nMCP: `oxygen_oxygents_activity`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_oxygents_activity"],"x-oxygen-cli-command":"oxygen oxygents activity"}},"/api/cli/teammates/{slug}/chat":{"post":{"operationId":"teammates.chat","tags":["Teammates"],"summary":"Oxygents chat","description":"Open the ongoing chat with an Oxygent, creating it the first time. Starts no inference.\n\nCLI: `oxygen oxygents chat`.\n\nMCP: `oxygen_oxygents_chat`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_chat"],"x-oxygen-cli-command":"oxygen oxygents chat"}},"/api/cli/teammates/{slug}/delete":{"post":{"operationId":"teammates.delete","tags":["Teammates"],"summary":"Oxygents delete","description":"Delete an Oxygent for good, for everyone: its profile, every chat with it (its group chats too, except those other people are in, which it leaves and where only its answers go), its routines, team memory and runs. What it made in the workspace stays. Its owner or a workspace admin only; never the first Oxygent. Preview first to see what would go, then delete with confirm set to its slug. Its slug stays taken afterwards. Free; cannot be undone.\n\nCLI: `oxygen oxygents delete`.\n\nMCP: `oxygen_oxygents_delete`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"preview":{"type":"boolean","description":"Only say what would go: its chats and the people they belong to, group chats, the group chats with other people it would leave, routines, runs, attached files and team memory entries."},"confirm":{"type":"string","maxLength":49,"description":"Its slug, repeated, to delete it."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_delete"],"x-oxygen-cli-command":"oxygen oxygents delete"}},"/api/cli/teammates/{slug}/duplicate":{"post":{"operationId":"teammates.duplicate","tags":["Teammates"],"summary":"Oxygents duplicate","description":"Copy an Oxygent as a new one you own, named \"<name> copy\" unless you name it: its job, look, instructions, skills and tool settings, but not its chats, memory, routines or who it is shared with. The copy defaults to Workspace; choose Personal for creator-only access. Free.\n\nCLI: `oxygen oxygents duplicate`.\n\nMCP: `oxygen_oxygents_duplicate`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"visibility":{"type":"string","enum":["workspace","personal"],"description":"Visibility of the copy; Workspace by default. No history is copied. Explicitly saving to team memory publishes that entry to the workspace."},"name":{"type":"string","minLength":1,"maxLength":80,"description":"What everyone calls the copy. Its slug is made from the name, and a deleted Oxygent's slug stays taken, so a copy can get a numbered one (scout-2)."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_duplicate"],"x-oxygen-cli-command":"oxygen oxygents duplicate"}},"/api/cli/teammates/{slug}/hide":{"post":{"operationId":"teammates.hide","tags":["Teammates"],"summary":"Oxygents hide","description":"Hide an Oxygent from your own sidebar, or show it again. Its chat is kept; only your sidebar changes. Free. The first Oxygent cannot be hidden.\n\nCLI: `oxygen oxygents hide`.\n\nMCP: `oxygen_oxygents_hide`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hidden":{"type":"boolean","description":"Off shows it again; on, or left out, hides it."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_hide"],"x-oxygen-cli-command":"oxygen oxygents hide"}},"/api/cli/teammates/{slug}/memory":{"get":{"operationId":"teammates.memory","tags":["Teammates"],"summary":"Oxygents memory","description":"List what the team asked an Oxygent to remember. Every chat with it reads this; it is a Knowledge page.\n\nCLI: `oxygen oxygents memory`.\n\nMCP: `oxygen_oxygents_memory`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_oxygents_memory"],"x-oxygen-cli-command":"oxygen oxygents memory"},"post":{"operationId":"teammates.remember","tags":["Teammates"],"summary":"Oxygents remember","description":"Add one thing to an Oxygent's team memory: every chat with it reads it, and the whole workspace can see it. Free.\n\nCLI: `oxygen oxygents remember`.\n\nMCP: `oxygen_oxygents_remember`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":500}},"required":["text"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_remember"],"x-oxygen-cli-command":"oxygen oxygents remember"}},"/api/cli/teammates/{slug}/memory/{entry_id}":{"delete":{"operationId":"teammates.forget","tags":["Teammates"],"summary":"Oxygents forget","description":"Remove one entry from an Oxygent's team memory.\n\nCLI: `oxygen oxygents forget`.\n\nMCP: `oxygen_oxygents_forget`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"entry_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_oxygents_forget"],"x-oxygen-cli-command":"oxygen oxygents forget"}},"/api/cli/teammates/{slug}/messages":{"post":{"operationId":"teammates.message","tags":["Teammates"],"summary":"Oxygents message","description":"Send a message in the ongoing chat with an Oxygent. Starts a turn billed from workspace credits; paid or external actions still need approval.\n\nCLI: `oxygen oxygents message`.\n\nMCP: `oxygen_oxygents_message`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":16000}},"required":["message"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_oxygents_message"],"x-oxygen-cli-command":"oxygen oxygents message"}},"/api/cli/teammates/{slug}/notes":{"get":{"operationId":"teammates.notes","tags":["Teammates"],"summary":"Oxygents notes","description":"Read what an Oxygent keeps about you. Private to you; never included in shared Workspace or multi-person group chats.\n\nCLI: `oxygen oxygents notes`.\n\nMCP: `oxygen_oxygents_notes`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_oxygents_notes"],"x-oxygen-cli-command":"oxygen oxygents notes"},"post":{"operationId":"teammates.notes_set","tags":["Teammates"],"summary":"Oxygents notes_set","description":"Replace what an Oxygent keeps about you; empty clears it. Private to you.\n\nCLI: `oxygen oxygents notes-set`.\n\nMCP: `oxygen_oxygents_notes_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","maxLength":4000}},"required":["notes"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_notes_set"],"x-oxygen-cli-command":"oxygen oxygents notes-set"}},"/api/cli/teammates/{slug}/notify":{"post":{"operationId":"teammates.notify","tags":["Teammates"],"summary":"Oxygents notify","description":"Turn your notifications from an Oxygent off, or back on: whether it notifies you when it finishes or waits on you. Only yours change (for an API key, those of the person who made it). Free.\n\nCLI: `oxygen oxygents notify`.\n\nMCP: `oxygen_oxygents_notify`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notify":{"type":"boolean","description":"Off silences it for you; on, or left out, turns them back on."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_notify"],"x-oxygen-cli-command":"oxygen oxygents notify"}},"/api/cli/teammates/{slug}/pin":{"post":{"operationId":"teammates.pin","tags":["Teammates"],"summary":"Oxygents pin","description":"Pin an Oxygent near the top of your own sidebar, or unpin it. Only your sidebar changes. Free.\n\nCLI: `oxygen oxygents pin`.\n\nMCP: `oxygen_oxygents_pin`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pinned":{"type":"boolean","description":"Off unpins it; on, or left out, pins it."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_pin"],"x-oxygen-cli-command":"oxygen oxygents pin"}},"/api/cli/teammates/{slug}/read":{"post":{"operationId":"teammates.read","tags":["Teammates"],"summary":"Oxygents read","description":"Mark your chat with an Oxygent read up to its newest turn (or turn_index), or mark its newest turn unread again. Free.\n\nCLI: `oxygen oxygents read`.\n\nMCP: `oxygen_oxygents_read`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"turn_index":{"type":"integer","minimum":0},"unread":{"type":"boolean","description":"On marks its newest turn unread again."}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_oxygents_read"],"x-oxygen-cli-command":"oxygen oxygents read"}},"/api/cli/teammates/{slug}/routines":{"get":{"operationId":"teammates.routines","tags":["Teammates"],"summary":"Oxygents routines","description":"List your routines with an Oxygent: schedule, status, next run and last report. Manage one with `agent session` (pause, resume).\n\nCLI: `oxygen oxygents routines`.\n\nMCP: `oxygen_oxygents_routines`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_oxygents_routines"],"x-oxygen-cli-command":"oxygen oxygents routines"}},"/api/cli/teammates/{slug}/tasks":{"post":{"operationId":"teammates.task","tags":["Teammates"],"summary":"Oxygents task","description":"Start a background task from your chat with an Oxygent: an unattended run of it, as you, within max_credits. Its result posts into the chat; it and the run are visible to the workspace. Requires approved:true.\n\nCLI: `oxygen oxygents task`.\n\nMCP: `oxygen_oxygents_task`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"goal":{"type":"string","minLength":1,"maxLength":4000,"description":"What the run does, without needing the chat."},"max_credits":{"type":"integer","minimum":1,"maximum":2000},"approved":{"type":"boolean","description":"true: you approve this run and its ceiling."},"proposal_id":{"type":"string","maxLength":64,"description":"The proposal from the chat this starts; starting it twice starts one run."}},"required":["title","goal","max_credits","approved"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_oxygents_task"],"x-oxygen-cli-command":"oxygen oxygents task"}},"/api/cli/templates":{"get":{"operationId":"getTemplates","tags":["Templates"],"summary":"List Prompt Templates","description":"Lists reusable prompt templates layered into AI columns at run time. Includes the seeded outreach-message-default template plus any workspace-authored templates.\n\nMCP: `oxygen_prompts_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","description":"Include archived templates."}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["ai_column_system","scoring_rubric","other"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_prompts_list"]}},"/api/cli/templates/archive":{"post":{"operationId":"postTemplatesArchive","tags":["Templates"],"summary":"Archive Prompt Template","description":"Archives a workspace-authored prompt template. Seeded OXYGEN defaults cannot be archived.\n\nMCP: `oxygen_prompts_archive`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"templateId":{},"template_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_prompts_archive"]}},"/api/cli/templates/get":{"post":{"operationId":"postTemplatesGet","tags":["Templates"],"summary":"Get Prompt Template","description":"Reads one prompt template by id or slug.\n\nMCP: `oxygen_prompts_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"templateId":{},"template_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_prompts_get"]}},"/api/cli/templates/upsert":{"post":{"operationId":"postTemplatesUpsert","tags":["Templates"],"summary":"Create or Update Prompt Template","description":"Creates or updates a reusable prompt template. AI columns reference templates via promptTemplateSlug.\n\nMCP: `oxygen_prompts_upsert`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{},"description":{},"id":{},"kind":{},"name":{},"slug":{},"template":{"type":"object","description":"Prompt template input. Provide id to update; omit to create.","properties":{"id":{"type":"string","description":"Existing template UUID when updating."},"slug":{"type":"string","description":"Stable slug, kebab-case."},"name":{"type":"string","minLength":1,"maxLength":240},"description":{"type":"string","maxLength":4000},"kind":{"type":"string","enum":["ai_column_system","scoring_rubric","other"]},"body":{"type":"string","minLength":1,"maxLength":200000}},"additionalProperties":false},"templateId":{},"template_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_prompts_upsert"]}},"/api/cli/tools/{toolId}":{"get":{"operationId":"getToolsToolId","tags":["Tools"],"summary":"Get Tool Descriptor","description":"Catalog metadata (summary default); choose view/native field keys. Named omissions; exact schemas. MCP schemas: oxygen_capabilities_schema. enumRef: oxygen_tools_enums_get.\n\nMCP: `oxygen_tools_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"toolId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tools_get"]}},"/api/cli/tools/check-access":{"post":{"operationId":"tools.check_access","tags":["Tools"],"summary":"Check Tool Access","description":"Read tool access for this workspace; verify_credential explicitly opts into a provider credential probe.\n\nCLI: `oxygen tools check-access`.\n\nMCP: `oxygen_tools_check_access`, `oxygen_tools_plan_table_batch`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tool_id":{"type":"string"},"connection_id":{"type":"string"},"credential_mode":{"type":"string","enum":["managed","user_api_key"]},"input":{"type":"object","additionalProperties":true},"verify_credential":{"type":"boolean"}},"required":["tool_id"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tools_check_access","oxygen_tools_plan_table_batch"],"x-oxygen-cli-command":"oxygen tools check-access"}},"/api/cli/tools/enums":{"get":{"operationId":"getToolsEnums","tags":["Tools"],"summary":"List Provider Enum Catalogs","description":"Lists provider enum catalogs (e.g. blitzapi industry, employee_range, country_code). Call before drafting payloads with enumRef fields so values match the provider contract.\n\nMCP: `oxygen_tools_enums_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"provider","in":"query","required":false,"schema":{"type":"string","description":"Optional provider filter, e.g. blitzapi.","maxLength":80}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tools_enums_list"]}},"/api/cli/tools/enums/{provider}/{enumRef}":{"get":{"operationId":"getToolsEnumsProviderEnumRef","tags":["Tools"],"summary":"Get Provider Enum Catalog","description":"Returns the accepted values for one provider enum catalog (e.g. blitzapi.industry, blitzapi.employee_range). Before calling oxygen_tools_run_dry / oxygen_tools_run_live or table ingestion on a tool whose descriptor lists enumRef fields, call this and use the exact values returned. Use the optional query to scope long catalogs (industry has 534 values).\n\nMCP: `oxygen_tools_enums_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"enumRef","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"number","description":"Maximum number of values to return. Defaults to 100. Maximum 1000.","minimum":1,"maximum":1000}},{"name":"q","in":"query","required":false,"schema":{}},{"name":"query","in":"query","required":false,"schema":{"type":"string","description":"Optional case-insensitive substring or token search to scope long catalogs (e.g. 'software' to find software-related industries).","maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tools_enums_get"]}},"/api/cli/tools/favorites":{"get":{"operationId":"tools.favorites","tags":["Tools"],"summary":"Tools favorites","description":"Read this member's favorite tool catalog entries in the active workspace.\n\nMCP: `oxygen_tool_favorites`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tool_favorites"]},"post":{"operationId":"postToolsFavorites","tags":["Tools"],"summary":"Favorite Catalog Entry","description":"Adds or removes one column-catalog entry from the caller's favourites for this workspace. Entry ids: find_email, preset:person_enrich, prompt:<key>, tool:<tool_id>.\n\nMCP: `oxygen_tools_favorite`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"entryId":{},"entry_id":{"type":"string","minLength":1,"maxLength":160},"favorite":{"type":"boolean"},"favourite":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_tools_favorite"]}},"/api/cli/tools/run":{"post":{"operationId":"postToolsRun","tags":["Tools"],"summary":"Run Tool (Dry Run)","description":"Validates without provider calls/credit spend; returns resolved input, output schema, credit estimate and cache status.\n\nMCP: `oxygen_adyntel_ads_search`, `oxygen_tools_run_dry`, `oxygen_tools_run_live`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{},"connectionId":{},"connection_id":{"type":"string","description":"Integration connection id override."},"credentialMode":{},"credential_mode":{"type":"string","description":"Credential mode override.","enum":["managed","user_api_key","user_oauth"]},"fields":{"type":"array","description":"Response paths for large outputs, e.g. ['response.results[].full_name','meta'].","items":{"type":"string"},"maxItems":100},"input":{"type":"object","description":"Must match tool input schema.","additionalProperties":true},"max_credits":{},"mode":{},"orgId":{},"org_id":{},"organizationId":{},"organization_id":{},"oxygenCursor":{},"oxygen_cursor":{"type":"string","description":"Previous live run's oxygen_next_cursor."},"request":{},"return":{"type":"string","description":"Legacy response shape alias. Prefer return_mode.","enum":["raw","compact","summary"]},"returnMode":{},"return_mode":{"type":"string","description":"Response shape; summary keeps headlines without large payloads.","enum":["raw","compact","summary"]},"toolId":{},"tool_id":{"type":"string","description":"Tool id, e.g. 'apollo.people_search'.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_adyntel_ads_search","oxygen_tools_run_dry","oxygen_tools_run_live"]}},"/api/cli/tools/search":{"get":{"operationId":"getToolsSearch","tags":["Tools"],"summary":"Search Tool Catalog","description":"Provider operations and priced native_columns (Table kinds/presets/waterfalls), different from oxygen_capabilities_search (goal/price ownership; start there). Public LinkedIn reads: native scraper.* operations; connected linkedin.*: private data/actions. Whole-card omissions named; narrow filters. oxygen_tools_get: price/schema/availability/routing.\n\nMCP: `oxygen_tools_search`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"capability","in":"query","required":false,"schema":{"type":"string","description":"Capability tag, e.g. mobile_phone or work_email.","maxLength":80}},{"name":"category","in":"query","required":false,"schema":{"type":"string","description":"Category, e.g. company_search, people_search, research, local.","maxLength":80}},{"name":"forTable","in":"query","required":false,"schema":{}},{"name":"for_table","in":"query","required":false,"schema":{"type":"string","description":"Table id/slug for priced native columns; deterministic suggestions first.","maxLength":200}},{"name":"limit","in":"query","required":false,"schema":{"type":"number","description":"Default 10.","minimum":1,"maximum":100}},{"name":"provider","in":"query","required":false,"schema":{"type":"string","description":"Exact provider id (e.g. blitzapi); one-provider inventory, no fuzzy matches.","maxLength":80}},{"name":"q","in":"query","required":false,"schema":{}},{"name":"query","in":"query","required":false,"schema":{"type":"string","description":"Search name/provider/capability/decision metadata; empty obeys limit unless all=true.","maxLength":200}},{"name":"verbosity","in":"query","required":false,"schema":{"type":"string","description":"minimal/terse default: compact ranks; summary: costs/decisions; full: schemas. One tool: oxygen_tools_get.","enum":["minimal","terse","summary","full"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_tools_search"]}},"/api/cli/ugc":{"get":{"operationId":"getUgc","tags":["UGC"],"summary":"UGC programs and creator work","description":"Read programs, creator memberships, posts, calendar/history, analytics, shared Knowledge, voice, sponsorship or host/peer amplification. post_history uses post_id + enrollment_version; voice, peer_amplification and draft_run use participation_id. Read-only, free and provider-free.\n\nMCP: `oxygen_ugc_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_ugc_get"]},"post":{"operationId":"postUgc","tags":["UGC"],"summary":"UGC personal voice","description":"Save your writing preferences/examples as a private provisional Knowledge voice. Free and provider-free; no connected account needed. Use voice get's expected_revision to edit. Knowledge approval gates still apply.\n\nMCP: `oxygen_ugc_amplification_reconcile`, `oxygen_ugc_amplification_save`, `oxygen_ugc_application_create`, `oxygen_ugc_application_decide`, `oxygen_ugc_comment_cancel`, `oxygen_ugc_comment_schedule`, `oxygen_ugc_creator_profile_update`, `oxygen_ugc_creator_target_update`, `oxygen_ugc_draft_create`, `oxygen_ugc_invite_accept`, `oxygen_ugc_invite_create`, `oxygen_ugc_invite_revoke`, `oxygen_ugc_invite_send`, `oxygen_ugc_participation_update`, `oxygen_ugc_peer_amplification_reconcile`, `oxygen_ugc_peer_amplification_save`, `oxygen_ugc_post_approve`, `oxygen_ugc_post_enroll`, `oxygen_ugc_post_remove`, `oxygen_ugc_post_update`, `oxygen_ugc_program_create`, `oxygen_ugc_program_delete`, `oxygen_ugc_program_duplicate`, `oxygen_ugc_program_update`, `oxygen_ugc_sponsorship_cancel`, `oxygen_ugc_sponsorship_confirm`, `oxygen_ugc_sponsorship_preview`, `oxygen_ugc_voice_import`, `oxygen_ugc_voice_save`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{},"action_id":{},"actions":{},"application_id":{},"approval_mode":{},"approve":{},"approved":{},"audience":{},"body":{"type":"string","description":"Writing preferences or voice guide."},"brief":{},"comment_id":{},"content_text":{},"decision":{},"delay_max_seconds":{},"delay_min_seconds":{},"description":{},"email":{},"email_message":{},"email_subject":{},"emails":{},"enabled":{},"enrollment_id":{},"enrollment_version":{},"expected_policy_version":{},"expected_revision":{"type":"integer","description":"Current revision when editing."},"import_id":{},"invitation_id":{},"join_policy":{},"knowledge_folder_ids":{},"knowledge_slugs":{},"linkedin_url":{},"max_actions_per_post":{},"max_credits":{},"max_credits_per_cycle":{},"message":{},"name":{},"outcome":{},"participant_sender_ids":{},"participation_id":{"type":"string","description":"Your participation ID."},"participation_ids":{},"peer_engagement_enabled":{},"post_id":{},"preview_token":{},"product_url":{},"program_id":{},"quote":{},"request_id":{},"risk_acknowledged":{},"scheduled_for":{},"send_email":{},"sender_account_id":{},"sender_voice_pages":{},"source_revision":{},"sponsor":{},"status":{},"text":{},"title":{},"token":{},"topic":{},"topics":{},"visibility":{},"voice_page_id":{},"writing_examples":{"type":"array","items":{"type":"string"},"description":"Up to five examples you wrote."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_ugc_amplification_reconcile","oxygen_ugc_amplification_save","oxygen_ugc_application_create","oxygen_ugc_application_decide","oxygen_ugc_comment_cancel","oxygen_ugc_comment_schedule","oxygen_ugc_creator_profile_update","oxygen_ugc_creator_target_update","oxygen_ugc_draft_create","oxygen_ugc_invite_accept","oxygen_ugc_invite_create","oxygen_ugc_invite_revoke","oxygen_ugc_invite_send","oxygen_ugc_participation_update","oxygen_ugc_peer_amplification_reconcile","oxygen_ugc_peer_amplification_save","oxygen_ugc_post_approve","oxygen_ugc_post_enroll","oxygen_ugc_post_remove","oxygen_ugc_post_update","oxygen_ugc_program_create","oxygen_ugc_program_delete","oxygen_ugc_program_duplicate","oxygen_ugc_program_update","oxygen_ugc_sponsorship_cancel","oxygen_ugc_sponsorship_confirm","oxygen_ugc_sponsorship_preview","oxygen_ugc_voice_import","oxygen_ugc_voice_save"]}},"/api/cli/unibox/metadata":{"get":{"operationId":"unibox.metadata","tags":["Unibox"],"summary":"Unibox metadata","description":"Read the complete authenticated inbox account, filter and tag metadata, including each sender profile (person) and its id.\n\nCLI: `oxygen unibox metadata`.\n\nMCP: `oxygen_unibox_metadata`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_unibox_metadata"],"x-oxygen-cli-command":"oxygen unibox metadata"}},"/api/cli/verify/run":{"post":{"operationId":"postVerifyRun","tags":["Verify"],"summary":"Verify Email","description":"Verify emails you already have. MillionVerifier answers first; catch-all (accept-all) domains escalate automatically to BounceBan. Per address: verdict (valid | invalid | catch_all | unknown), deliverable, resolving provider, attempt trace. valid = send-safe; catch_all = domain accepts everything; unknown = no verifier answered, NOT a bad address. dry_run previews free.\n\nMCP: `oxygen_verify_email`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{},"emails":{"type":"array","description":"Addresses to verify (max 100).","items":{"type":"string","minLength":3,"maxLength":320},"minItems":1,"maxItems":100},"max_credits":{"type":"number","description":"Required for live; caps Oxygen credits, not own-key spend.","exclusiveMinimum":0},"mode":{"type":"string","enum":["dry_run","live"],"description":"dry_run (default) previews free; live bills and needs max_credits."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_verify_email"]}},"/api/cli/visuals/assets":{"post":{"operationId":"postVisualsAssets","tags":["Visuals"],"summary":"Upload Media Asset","description":"Prepare a private asset upload (name, size_bytes, sha256), PUT bytes to upload_url, then complete with file_id. Resume refreshes the same reservation using file_id and its original metadata; already_uploaded skips transfer. Up to 100 MiB. Stores images, fonts, audio/video and reusable HTML/CSS/JS components without executing them. Bind ready file IDs to relative paths in a render preview.\n\nMCP: `oxygen_visual_asset_upload`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["prepare","resume","complete"]},"file_id":{"type":"string","description":"Tenant-owned workspace file UUID."},"name":{"type":"string"},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"size_bytes":{"type":"integer","minimum":1,"maximum":104857600}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_visual_asset_upload"]}},"/api/cli/visuals/files/{fileId}":{"get":{"operationId":"getVisualsFilesFileId","tags":["Visuals"],"summary":"Read Visual File","description":"Read a visual file's metadata, editable source when HTML, provenance and authenticated download URL in the current workspace.\n\nMCP: `oxygen_visual_file_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_visual_file_get"]}},"/api/cli/visuals/files/{fileId}/download":{"get":{"operationId":"visuals.download","tags":["Visuals"],"summary":"Visuals download","description":"Download a tenant-owned visual file as an MCP resource with base64 bytes (max 50 MiB). Use web or CLI for larger originals.\n\nMCP: `oxygen_visual_file_download`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"fileId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_visual_file_download"]}},"/api/cli/visuals/renders":{"post":{"operationId":"postVisualsRenders","tags":["Visuals"],"summary":"Preview Visual Render","description":"Save a durable preview record for static PNG/PDF or Hyperframes MP4: workspace write, 0 credits, no compute. Bind images, fonts and components to relative paths. Returns exact hashes and scope_hash. Hyperframes uses one source, scale 1, 24/30 fps, up to 10 seconds. No network or package installation.\n\nMCP: `oxygen_visual_render_preview`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"assets":{"type":"array","maxItems":64,"items":{"type":"object","properties":{"file_id":{"type":"string","description":"Tenant-owned workspace file UUID."},"path":{"type":"string","maxLength":200}},"additionalProperties":false,"required":["file_id","path"]}},"duration":{"type":"number","exclusiveMinimum":0,"maximum":10},"formats":{"type":"array","items":{"type":"string","enum":["png","pdf","mp4"]},"minItems":1,"maxItems":2},"fps":{"oneOf":[{"type":"integer","minimum":24,"maximum":24},{"type":"integer","minimum":30,"maximum":30}]},"height":{"type":"integer","minimum":1,"maximum":4096},"profile":{"type":"string","enum":["static","hyperframes"]},"scale":{"type":"integer","minimum":1,"maximum":2},"source_file_ids":{"type":"array","items":{"type":"string","description":"Tenant-owned workspace file UUID."},"minItems":1,"maxItems":12},"width":{"type":"integer","minimum":1,"maximum":4096}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_visual_render_preview"]}},"/api/cli/visuals/renders/{id}":{"get":{"operationId":"getVisualsRendersId","tags":["Visuals"],"summary":"Read Visual Render","description":"Read durable visual-render status, outputs, provenance and downloads. An effect_unknown run never repeats compute automatically. Read again while queued/running.\n\nMCP: `oxygen_visual_asset_upload`, `oxygen_visual_file_get`, `oxygen_visual_image_view`, `oxygen_visual_render_get`, `oxygen_visual_render_preview`, `oxygen_visual_source_create`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_visual_asset_upload","oxygen_visual_file_get","oxygen_visual_image_view","oxygen_visual_render_get","oxygen_visual_render_preview","oxygen_visual_source_create"]},"post":{"operationId":"postVisualsRendersId","tags":["Visuals"],"summary":"Start Visual Render","description":"Start one exact render preview: free, bounded isolated compute. Pass its id and scope_hash. Repeating the same preview ID returns the existing job without another render. Poll oxygen_visual_render_get; inspect returned PNGs before finalizing. Publishing is separate.\n\nMCP: `oxygen_visual_render_start`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"render_id":{"type":"string","description":"Render preview/run UUID returned by oxygen_visual_render_preview."},"scope_hash":{"type":"string"}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_visual_render_start"]},"delete":{"operationId":"deleteVisualsRendersId","tags":["Visuals"],"summary":"Cancel Visual Render","description":"Request cancellation of one render. Queued jobs stop before compute; running jobs stop at a bounded cancellation checkpoint. Read the job to verify terminal status.\n\nMCP: `oxygen_visual_render_cancel`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_visual_render_cancel"]}},"/api/cli/visuals/sources":{"post":{"operationId":"postVisualsSources","tags":["Visuals"],"summary":"Save Visual Source","description":"Save immutable editable source. html contains the source text; source_type selects an HTML composition (default) or reusable css/javascript/json component. Supply parent_file_id for a revision. No code executes; max 1.5 MB. Bind component file IDs to project paths in a render preview.\n\nMCP: `oxygen_visual_source_create`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"composition":{"type":"object","additionalProperties":true,"description":"Saved layout/output/timing/assets, using the render-preview field names without source_file_ids."},"html":{"type":"string"},"name":{"type":"string"},"parent_file_id":{"type":"string","description":"Tenant-owned workspace file UUID."},"source_type":{"type":"string","enum":["html","css","javascript","json"]}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_visual_source_create"]}},"/api/cli/voice/numbers":{"get":{"operationId":"getVoiceNumbers","tags":["Voice"],"summary":"Phone Numbers","description":"The org's dialing pool. No action lists each number with warm-up state, daily cap, dials left today and monthly credits (a number whose reservation is unpaid carries `reservation` and dials nothing), optionally narrowed by tag. action=search finds numbers to buy and action=requirements names a country's purchase rules; both are free. action=buy starts a RECURRING monthly charge per number (count 1-10 or phone_numbers), so it previews unless approved=true. action=release returns a number to the carrier — IRREVERSIBLE, previews unless approved=true. action=tag replaces its workspace tags ([] clears). action=cap sets its daily dial cap (1-300, default 100). Calls are placed by a rep in the web softphone.\n\nMCP: `oxygen_voice_numbers`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_voice_numbers"]},"post":{"operationId":"postVoiceNumbers","tags":["Voice"],"summary":"Phone Numbers","description":"The org's dialing pool. No action lists each number with warm-up state, daily cap, dials left today and monthly credits (a number whose reservation is unpaid carries `reservation` and dials nothing), optionally narrowed by tag. action=search finds numbers to buy and action=requirements names a country's purchase rules; both are free. action=buy starts a RECURRING monthly charge per number (count 1-10 or phone_numbers), so it previews unless approved=true. action=release returns a number to the carrier — IRREVERSIBLE, previews unless approved=true. action=tag replaces its workspace tags ([] clears). action=cap sets its daily dial cap (1-300, default 100). Calls are placed by a rep in the web softphone.\n\nMCP: `oxygen_voice_numbers`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","description":"Omit to list. search, requirements, buy, release, tag or cap."},"approved":{"type":"string","description":"buy/release: 'true' to act. Omit for a preview."},"area_code":{"type":"string","description":"search/buy: e.g. 415."},"count":{"type":"number","description":"buy: how many to pick, 1-10."},"end_user_type":{"type":"string","description":"requirements: business (default) or individual."},"in_region":{"type":"string","description":"search/buy: region such as CA."},"iso_country":{"type":"string","description":"search/buy/requirements: default US."},"limit":{"type":"integer","minimum":1,"maximum":30,"description":"search: maximum available numbers, 1-30; defaults to 10."},"phone_number":{"type":"string","description":"release/tag/cap: E.164 number to act on."},"phone_numbers":{"type":"array","items":{"type":"string"},"description":"buy: exact E.164 numbers from a search."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_voice_numbers"]}},"/api/cli/voice/numbers/{id}/cap":{"patch":{"operationId":"patchVoiceNumbersIdCap","tags":["Voice"],"summary":"Phone Numbers","description":"The org's dialing pool. No action lists each number with warm-up state, daily cap, dials left today and monthly credits (a number whose reservation is unpaid carries `reservation` and dials nothing), optionally narrowed by tag. action=search finds numbers to buy and action=requirements names a country's purchase rules; both are free. action=buy starts a RECURRING monthly charge per number (count 1-10 or phone_numbers), so it previews unless approved=true. action=release returns a number to the carrier — IRREVERSIBLE, previews unless approved=true. action=tag replaces its workspace tags ([] clears). action=cap sets its daily dial cap (1-300, default 100). Calls are placed by a rep in the web softphone.\n\nMCP: `oxygen_voice_numbers`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"daily_cap":{"type":"number","description":"cap: dials per day, 1-300."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_voice_numbers"]}},"/api/cli/voice/numbers/{id}/tags":{"post":{"operationId":"postVoiceNumbersIdTags","tags":["Voice"],"summary":"Phone Numbers","description":"The org's dialing pool. No action lists each number with warm-up state, daily cap, dials left today and monthly credits (a number whose reservation is unpaid carries `reservation` and dials nothing), optionally narrowed by tag. action=search finds numbers to buy and action=requirements names a country's purchase rules; both are free. action=buy starts a RECURRING monthly charge per number (count 1-10 or phone_numbers), so it previews unless approved=true. action=release returns a number to the carrier — IRREVERSIBLE, previews unless approved=true. action=tag replaces its workspace tags ([] clears). action=cap sets its daily dial cap (1-300, default 100). Calls are placed by a rep in the web softphone.\n\nMCP: `oxygen_voice_numbers`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":80},"description":"tag only: the full workspace tag list to set ([] clears)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_voice_numbers"]}},"/api/cli/voice/tasks":{"get":{"operationId":"getVoiceTasks","tags":["Voice"],"summary":"List Call Queue","description":"Lists the call queue: leads waiting for a human to dial, queued by sequence call steps, CRM records, table rows, replies, or by hand. Best-first (priority, then due). Read-only, 0 credits.\n\nMCP: `oxygen_voice_tasks_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"assigned_user_id","in":"query","required":false,"schema":{}},{"name":"limit","in":"query","required":false,"schema":{"type":"string","description":"Max tasks (1-200; default 50)."}},{"name":"sequence_id","in":"query","required":false,"schema":{"type":"string","description":"Only tasks queued by this sequence."}},{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Filter by origin: sequence, crm, table, reply, manual."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated: pending, claimed, completed, skipped, canceled."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_voice_tasks_list"]},"post":{"operationId":"postVoiceTasks","tags":["Voice"],"summary":"Work Call Queue","description":"Moves one call task through the queue. queue puts a lead IN (needs lead_phone; idempotent, an already-queued lead returns created:false; warnings names anything undialable). claim takes the next due task (or task_id) and returns a lease_token; a task someone else holds fails rather than being stolen, so two reps never dial the same prospect. complete needs that lease_token plus a disposition and resumes any enrollment parked on the call; extend renews the 15-min lease for a long call. skip drops a task without dialing. override waives one guardrail for one lead. Calls nobody answered self-disposition, so complete/skip may return already_recorded:true — success, not conflict. Tasks carry dialable/block_reason/block_detail/override_flag. Never places a call.\n\nMCP: `oxygen_voice_tasks_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","description":"queue, claim, complete, extend, skip, or override."},"assigned_user_id":{"type":"string","description":"queue: workspace user assigned this task."},"crm_record_id":{"type":"string","description":"queue: bind to a CRM record."},"disposition":{"type":"string","description":"complete. One of: connected, no_answer, voicemail, busy, wrong_number, not_interested, callback_requested, meeting_booked, do_not_call, failed."},"due_at":{"type":"string","description":"queue: ISO-8601; held out of the queue until then."},"guardrail":{"type":"string","description":"override: calling_window, unknown_timezone, daily_cap, or none. DNC, credits, health and destinations are never waivable."},"guardrail_overrides":{},"lead_name":{"type":"string","description":"queue: name shown on the dial screen."},"lead_phone":{"type":"string","description":"queue: E.164 number (+ then 2-15 digits). Required."},"lead_timezone":{"type":"string","description":"queue: IANA zone (America/New_York). Without it the calling-window guardrail fails closed and the lead is undialable."},"lease_token":{"type":"string","description":"complete/extend: the lease_token from claim."},"note":{"type":"string","description":"queue: talking points for the rep; never sent to the lead."},"notes":{"type":"string","description":"complete: free-text call notes."},"overrides":{},"priority":{"type":"string","description":"queue: higher sorts first."},"reason":{"type":"string","description":"skip: why it was skipped."},"row_id":{"type":"string","description":"queue: bind to a table row."},"sequence_id":{"type":"string","description":"claim: restrict to this sequence's queue."},"source":{"type":"string","description":"queue: manual (default), crm, table, reply, sequence."},"subject_external_id":{"type":"string","description":"queue: that provider person id; pair with subject_provider."},"subject_provider":{"type":"string","description":"queue: external CRM provider; pair with subject_external_id."},"table_id":{"type":"string","description":"queue: bind to a table."},"task_id":{"type":"string","description":"Required for complete/extend/skip; optional for claim (default: next due)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_voice_tasks_update"]}},"/api/cli/voice/verification":{"get":{"operationId":"getVoiceVerification","tags":["Voice"],"summary":"Business Verification","description":"Business verification (a Twilio regulatory bundle) unlocks local numbers in GB, DE, AT, CH and FR. No action lists every country's state: instant, verification status (not_started, draft, in-review, twilio-approved, twilio-rejected with the reviewer's reason) or unavailable with the reason (NL, ES, IT, PL). action=submit sends business_fields, the registered address and documents (base64) for review; read the form from oxygen_voice_numbers action=requirements (its plan: field keys, address, upload slots). Submit previews unless approved='true'; a submission cannot be edited and review takes about three business days. No credits.\n\nMCP: `oxygen_voice_verification`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_voice_verification"]},"post":{"operationId":"postVoiceVerification","tags":["Voice"],"summary":"Business Verification","description":"Business verification (a Twilio regulatory bundle) unlocks local numbers in GB, DE, AT, CH and FR. No action lists every country's state: instant, verification status (not_started, draft, in-review, twilio-approved, twilio-rejected with the reviewer's reason) or unavailable with the reason (NL, ES, IT, PL). action=submit sends business_fields, the registered address and documents (base64) for review; read the form from oxygen_voice_numbers action=requirements (its plan: field keys, address, upload slots). Submit previews unless approved='true'; a submission cannot be edited and review takes about three business days. No credits.\n\nMCP: `oxygen_voice_verification`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","description":"Omit to list; submit to preview or send."},"address":{"type":"object","properties":{"customer_name":{"type":"string"},"street":{"type":"string"},"city":{"type":"string"},"region":{"type":"string"},"postal_code":{"type":"string"}},"additionalProperties":false,"description":"submit: registered address, when the plan needs one."},"approved":{"type":"string","description":"submit: 'true' to send for review. Omit for a validated preview."},"business_fields":{"type":"object","additionalProperties":{"type":"string"},"description":"submit: values keyed by the plan's field keys."},"documents":{"type":"array","maxItems":3,"items":{"type":"object","properties":{"slot":{"type":"string","description":"The plan's upload slot key."},"document_type":{"type":"string","description":"One of the slot's accepted types; defaults to its first."},"file_name":{"type":"string"},"content_type":{"type":"string","description":"application/pdf, image/jpeg or image/png."},"content_base64":{"type":"string","description":"File bytes, base64, under 5 MB."}},"required":["slot","content_base64"],"additionalProperties":false},"description":"submit: one file per upload slot."},"email":{"type":"string","description":"submit: review updates go here; defaults to the representative email field."},"iso_country":{"type":"string","description":"submit: GB, DE, AT, CH or FR."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_voice_verification"]}},"/api/cli/whatsapp/accounts":{"get":{"operationId":"getWhatsappAccounts","tags":["Whatsapp"],"summary":"List WhatsApp Accounts","description":"Read stored WhatsApp accounts (disconnected hidden by default; presence is not send readiness), health, warm-up and usage. include_disconnected includes retained accounts; status takes precedence. Use summary then exact account_id/value for long metadata. Direct sends are warm-only; cold initiation requires a Sequence with whatsapp_cold_initiate.\n\nMCP: `oxygen_whatsapp_accounts_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"include_disconnected","in":"query","required":false,"schema":{"type":"boolean","description":"Include retained disconnected accounts; default false. Presence is not send readiness."}},{"name":"include_usage","in":"query","required":false,"schema":{"type":"boolean","description":"Stored usage counts; default true."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","paused","disconnected","restricted","credentials_required"],"description":"Exact sender status; takes precedence over include_disconnected."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_whatsapp_accounts_list"]}},"/api/cli/whatsapp/accounts/{id}":{"get":{"operationId":"getWhatsappAccountsId","tags":["Whatsapp"],"summary":"Get WhatsApp Account","description":"Gets one WhatsApp account with full limits, the warm-up ramp state (account age + today's effective send ceiling), daily-reset timezone, and usage. Direct sends are warm-only; explicitly opted-in WhatsApp Sequences share these same limits. id accepts a WhatsApp account id, connection id, or Unipile account id.\n\nMCP: `oxygen_whatsapp_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_whatsapp_get"]},"delete":{"operationId":"deleteWhatsappAccountsId","tags":["Whatsapp"],"summary":"Disconnect WhatsApp Account","description":"Disconnects a WhatsApp account so it stops sending and reading immediately. Reconnect later with oxygen_whatsapp_connect (reconnect_connection_id) — note reconnecting restarts the warm-up ramp. id accepts a WhatsApp account id, connection id, or Unipile account id.\n\nMCP: `oxygen_whatsapp_disconnect`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_disconnect"]}},"/api/cli/whatsapp/accounts/{id}/limits":{"get":{"operationId":"getWhatsappAccountsIdLimits","tags":["Whatsapp"],"summary":"Get WhatsApp Account Limits","description":"Reads the per-account limits envelope: current effective limits, the org's overrides, the warm-up ramp schedule and today's effective send ceiling, the direct-send versus Sequence cold-initiation policy, the daily-reset timezone, plus system defaults and safe maximums. Read this before oxygen_whatsapp_limits_set so proposed values are not silently clamped by the ramp. id accepts a WhatsApp account id, connection id, or Unipile account id.\n\nMCP: `oxygen_whatsapp_limits_get`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_whatsapp_limits_get"]},"patch":{"operationId":"patchWhatsappAccountsIdLimits","tags":["Whatsapp"],"summary":"Set WhatsApp Account Limits","description":"Updates per-account daily caps for WhatsApp sends (max 40/day) AND reads, plus action spacing and the daily-reset timezone. Values are clamped to conservative safe maximums to protect the account. The mandatory warm-up ceiling (5→10→15→20/day by account age) always wins when lower — raising messages_per_day cannot bypass it. Direct sends remain warm-only; cold initiation is configured on a WhatsApp Sequence with whatsapp_cold_initiate and shares these caps.\n\nMCP: `oxygen_whatsapp_limits_set`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limits":{"type":"object","description":"Per-account daily/spacing caps for WhatsApp sends AND reads. They cover direct warm sends and opted-in WhatsApp Sequence actions. WhatsApp uses the unofficial linked-device protocol with real account-ban risk, so caps are conservative and clamped server-side. A MANDATORY warm-up ceiling is enforced at send time: day 0-2 → 5/day, day 3-6 → 10/day, day 7-13 → 15/day, day 14+ → 20/day. The effective daily send cap is min(your configured cap, the ramp cap for the account's age). Cold initiation is configured on the Sequence with whatsapp_cold_initiate, not in this account-limit object.","additionalProperties":false,"properties":{"messages_per_day":{"type":"integer","minimum":0,"maximum":40,"description":"Max 40 (default 20). Daily WhatsApp messages across direct warm traffic and opted-in Sequence actions. Ramp: days 0–2: 5; 3–6: 10; 7–13: 15; 14+: configured cap (20 default, 40 maximum). New outreach waits 24 hours after connection or reconnection."},"likes_per_day":{"type":"integer","minimum":0,"maximum":40,"description":"Max 40 (default 20). Daily reactions."},"messages_reads_per_day":{"type":"integer","minimum":0,"maximum":600,"description":"Max 600 (default 200). Chat and message-history reads."},"relations_reads_per_day":{"type":"integer","minimum":0,"maximum":100,"description":"Max 100 (default 40). Chat-list reads."},"total_actions_per_day":{"type":"integer","minimum":0,"maximum":80,"description":"Max 80 (default 40). All sends: messages, reactions and edits."},"total_reads_per_day":{"type":"integer","minimum":0,"maximum":700,"description":"Max 700 (default 240). All reads."},"min_action_spacing_seconds":{"type":"integer","minimum":600,"maximum":3600,"description":"Max 3600 (default 600). Minimum seconds between WhatsApp actions."},"action_spacing_jitter_seconds":{"type":"integer","minimum":0,"maximum":1800,"description":"Max 1800 (default 300). Random seconds added on top of the spacing floor."}}},"randomize_daily_caps":{},"read_warmup":{},"warmup_preset":{},"weekend_full_volume":{},"working_hours":{"type":"object","description":"Per-account time settings. The only field that affects sending is the timezone the daily action counters reset in.","additionalProperties":false,"properties":{"timezone":{"type":"string","description":"IANA timezone the daily action counters reset in, e.g. America/New_York."}}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_limits_set"]}},"/api/cli/whatsapp/accounts/sync":{"post":{"operationId":"postWhatsappAccountsSync","tags":["Whatsapp"],"summary":"Sync WhatsApp Accounts","description":"Refreshes account health/status from Unipile for all (or one) connected WhatsApp accounts.\n\nMCP: `oxygen_whatsapp_sync`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{},"connection_id":{"type":"string","description":"Optional control-plane connection id to sync a single account instead of all."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_sync"]}},"/api/cli/whatsapp/chats/{chatId}/action":{"post":{"operationId":"postWhatsappChatsChatIdAction","tags":["Whatsapp"],"summary":"Act on a WhatsApp Chat","description":"Acts on one WhatsApp chat (see the action enum). Status/label actions apply locally and run immediately; addParticipant, removeParticipant and getInviteLink are visible to others and APPROVAL-GATED (preview unless approved). value: true/false for status actions, a participant id for membership, label text for setLabel; omit for getInviteLink.\n\nMCP: `oxygen_whatsapp_chat_action`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"chatId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Connected WhatsApp account; only needed when several are connected."},"account_id":{},"action":{"type":"string","enum":["setReadStatus","setMuteStatus","setArchiveStatus","setPinnedStatus","setLabel","addParticipant","removeParticipant","getInviteLink"],"description":"Action to perform."},"approved":{"type":"boolean","description":"Required for addParticipant/removeParticipant/getInviteLink."},"value":{"type":"string","description":"See description. Omit for getInviteLink."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_chat_action"]}},"/api/cli/whatsapp/chats/{chatId}/sync":{"post":{"operationId":"postWhatsappChatsChatIdSync","tags":["Whatsapp"],"summary":"Backfill a WhatsApp Conversation's History","description":"Backfills ONE WhatsApp conversation's message history; call again with the same chat_id to poll. The only history backfill WhatsApp has (oxygen_whatsapp_sync refreshes account status, not messages). Returns status SYNC_STARTED|RUNNING|DONE|ERROR|CHAT_DELETED plus in_progress. Spends message-read budget.\n\nMCP: `oxygen_whatsapp_history_sync`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"chatId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Connected WhatsApp account; only needed when several are connected."},"account_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_history_sync"]}},"/api/cli/whatsapp/connect":{"post":{"operationId":"postWhatsappConnect","tags":["Whatsapp"],"summary":"Connect WhatsApp Account","description":"Creates pending WhatsApp authorization for QR/phone pairing where supported; users complete it in their browser. Price inspection: oxygen_billing_commitments view=connection-prices. reconnect_connection_id reconnects an account. New accounts start mandatory warm-up.\n\nMCP: `oxygen_whatsapp_connect`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"pairingPhoneNumber":{},"pairing_phone_number":{"type":"string","description":"International number for phone-number pairing where supported.","minLength":1},"reconnectConnectionId":{},"reconnect_connection_id":{"type":"string","description":"Control-plane connection id to reconnect instead of linking a new account."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_connect"]}},"/api/cli/whatsapp/draft":{"post":{"operationId":"whatsapp.draft","tags":["Whatsapp"],"summary":"Draft a WhatsApp Message in Your Voice","description":"Generate a WhatsApp reply draft in the workspace voice, or approve a reviewed draft for an existing chat. Draft generation uses managed AI credits.\n\nCLI: `oxygen whatsapp draft`.\n\nMCP: `oxygen_whatsapp_draft`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"conversation_id":{"type":"string"},"goal":{"type":"string"},"row_id":{"type":"string"},"object":{"type":"string"},"approved":{"type":"boolean"},"draft_id":{"type":"string"},"text":{"type":"string"}},"required":["conversation_id"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_draft"],"x-oxygen-cli-command":"oxygen whatsapp draft"}},"/api/cli/whatsapp/drafts":{"get":{"operationId":"whatsapp.drafts.list","tags":["Whatsapp"],"summary":"List WhatsApp Drafts","description":"Read stored WhatsApp agent drafts; personal composer drafts stay private. Use summary and exact draft_id/value for long content.\n\nCLI: `oxygen whatsapp drafts list`.\n\nMCP: `oxygen_whatsapp_drafts_list`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"CSV current statuses: queued,edited,approved,sent,rejected; default queued,edited. No transition audit."}},{"name":"conversation","in":"query","required":false,"schema":{"type":"string","description":"Legacy local WhatsApp conversation UUID alias."}},{"name":"conversation_id","in":"query","required":false,"schema":{"type":"string","description":"Local WhatsApp conversation UUID; takes precedence over conversation. Retired native refs remain valid."}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Default 50; native maximum 200."}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Matching agent draft offset; live changes can shift pages."}},{"name":"draft_id","in":"query","required":false,"schema":{"type":"string","description":"Exact eligible agent draft UUID under the same status/conversation filters."}},{"name":"projection","in":"query","required":false,"schema":{"type":"string","enum":["summary","full","value"],"description":"summary: metadata without long values; full: complete rows; value: lossless JSON fragments for one exact selection. Omit for legacy output."}},{"name":"path","in":"query","required":false,"schema":{"type":"string","maxLength":1024,"description":"value: JSON Pointer into the public native result; empty selects the whole result."}},{"name":"value_cursor","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":2000,"description":"value: previous next_value_cursor with identical selection and path. Changed source refuses continuation."}},{"name":"max_chars","in":"query","required":false,"schema":{"type":"integer","minimum":1000,"maximum":40000,"description":"Opt-in complete receipt limit. MCP caps external at 10000, built-in at 4000. Oversize values remain accessible with value windows."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_whatsapp_drafts_list"],"x-oxygen-cli-command":"oxygen whatsapp drafts list"}},"/api/cli/whatsapp/drafts/reject":{"post":{"operationId":"whatsapp.drafts.reject","tags":["Whatsapp"],"summary":"Reject a WhatsApp Draft","description":"Reject an open WhatsApp draft without sending it.\n\nCLI: `oxygen whatsapp drafts reject`.\n\nMCP: `oxygen_whatsapp_draft_reject`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"draft_id":{"type":"string"},"reason":{"type":"string"}},"required":["draft_id"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_draft_reject"],"x-oxygen-cli-command":"oxygen whatsapp drafts reject"}},"/api/cli/whatsapp/drafts/update":{"post":{"operationId":"whatsapp.drafts.update","tags":["Whatsapp"],"summary":"Edit a WhatsApp Draft","description":"Edit an open WhatsApp draft before approving or sending it.\n\nCLI: `oxygen whatsapp drafts update`.\n\nMCP: `oxygen_whatsapp_draft_update`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"draft_id":{"type":"string"},"text":{"type":"string"}},"required":["draft_id","text"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_draft_update"],"x-oxygen-cli-command":"oxygen whatsapp drafts update"}},"/api/cli/whatsapp/messages/{messageId}/forward":{"post":{"operationId":"postWhatsappMessagesMessageIdForward","tags":["Whatsapp"],"summary":"Forward a WhatsApp Message","description":"Forwards a WhatsApp message into another chat. Delivers a NEW message: spends send budget, bounded by the warm-up ramp, APPROVAL-GATED (previews unless approved). WhatsApp only.\n\nMCP: `oxygen_whatsapp_forward`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"messageId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Connected WhatsApp account; only needed when several are connected."},"account_id":{},"approved":{"type":"boolean","description":"Set true to apply. Omit for a preview."},"chat_id":{},"toChatId":{},"to_chat_id":{"type":"string","description":"Destination Unipile chat id."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_forward"]}},"/api/cli/whatsapp/profile":{"get":{"operationId":"getWhatsappProfile","tags":["Whatsapp"],"summary":"Show the WhatsApp Profile","description":"Reads the connected number's own WhatsApp profile: display name, About/status, picture, business flag.\n\nMCP: `oxygen_whatsapp_profile_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"account","in":"query","required":false,"schema":{"type":"string","description":"Connected WhatsApp account; only needed when several are connected."}},{"name":"account_id","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_whatsapp_profile_get"]},"patch":{"operationId":"patchWhatsappProfile","tags":["Whatsapp"],"summary":"Edit the WhatsApp Profile","description":"Edits the connected number's own WhatsApp profile (the only three fields WhatsApp allows). APPROVAL-GATED: every contact sees the change, so it previews unless approved. Pass at least one field.\n\nMCP: `oxygen_whatsapp_profile_update`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"about":{"type":"string","description":"New About/status text."},"account":{"type":"string","description":"Connected WhatsApp account; only needed when several are connected."},"account_id":{},"approved":{"type":"boolean","description":"Set true to apply. Omit for a preview."},"displayName":{},"display_name":{"type":"string","description":"New display name."},"pictureUrl":{},"picture_url":{"type":"string","description":"New picture (file path or URL)."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_profile_update"]}},"/api/cli/whatsapp/warm-send":{"post":{"operationId":"postWhatsappWarmSend","tags":["Whatsapp"],"summary":"Send a Warm WhatsApp Message","description":"Sends ONE warm WhatsApp message to a contact who ALREADY has a WhatsApp conversation with a connected account. This tool is warm-only and approval-gated: the target must resolve to an existing network='whatsapp' conversation or attendee — a cold phone number with no prior conversation is REJECTED. For cold outreach, create a WhatsApp Sequence and explicitly enable whatsapp_cold_initiate; do not use this tool. This is a REAL external write: call once with approved=false (default) to preview, then again with approved=true to actually send. Never send without showing the user the preview first.\n\nMCP: `oxygen_whatsapp_warm_send`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string","description":"Connected WhatsApp account id, connection id, Unipile account id, or display-name ref that owns the existing conversation."},"approved":{"type":"boolean","description":"Set true to actually send. Omit/false returns a preview only."},"conversation_id":{},"target":{"type":"string","description":"Alias for an existing WhatsApp conversation id or Unipile chat id."},"text":{"type":"string","description":"Message text to send.","minLength":1}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_whatsapp_warm_send"]}},"/api/cli/whoami":{"get":{"operationId":"getWhoami","tags":["Whoami"],"summary":"Who Am I","description":"Returns the authorized organization and user; for an org API key, `user` is its issuing person and owns Personal Oxygents created here. Factual `onboarding` markers: a null block means unknown. No GTM prescription; discover requested motions through Recipes or Blueprints.\n\nMCP: `oxygen_whoami`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_whoami"]}},"/api/cli/worker/failures":{"get":{"operationId":"getWorkerFailures","tags":["Worker"],"summary":"List Worker Failures","description":"Lists failed background worker items — table action runs, table ingestions, and Postgres-queue jobs — with failure reasons and counts. Use after oxygen_worker_queue_stats reports failures to inspect what went wrong.\n\nMCP: `oxygen_worker_failures`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum failed items per queue. Defaults to 25; server caps at 100.","minimum":1,"maximum":100}},{"name":"queue","in":"query","required":false,"schema":{"type":"string","description":"Which queue to inspect. all (default) covers everything; actions = table action runs; ingestions = table ingestions; postgres_queue = background jobs.","enum":["all","actions","ingestions","postgres_queue"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_worker_failures"]}},"/api/cli/worker/queue-stats":{"get":{"operationId":"getWorkerQueueStats","tags":["Worker"],"summary":"Get Worker Queue Stats","description":"Returns background worker queue health for table action runs, table ingestions, and workflows, including active worker ids and worker type (Fly worker, Vercel Queue, Vercel cron, or manual). Use when a run is stale queued or no worker has leased work.\n\nMCP: `oxygen_worker_queue_stats`, `oxygen_workflows_tail`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_worker_queue_stats","oxygen_workflows_tail"]}},"/api/cli/worker/repair":{"post":{"operationId":"worker.repair","tags":["Worker"],"summary":"Worker repair","description":"Repair this workspace's stalled execution queues through the native bounded recovery path.\n\nMCP: `oxygen_workspace_queue_repair`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workspace_queue_repair"]}},"/api/cli/workflows":{"get":{"operationId":"getWorkflows","tags":["Workflows"],"summary":"List Workflows","description":"Lists workflows; optionally filter by tag. Newest 200 by default; see `capped`.\n\nMCP: `oxygen_workflows_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"node_testable","in":"query","required":false,"schema":{}},{"name":"search","in":"query","required":false,"schema":{}},{"name":"tag","in":"query","required":false,"schema":{"type":"string","description":"Only workflows carrying this workspace tag (Tags primitive; see oxygen_tags_list)."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflows_list"]}},"/api/cli/workflows/{slug}/observed-output":{"get":{"operationId":"workflows.observed_output","tags":["Workflows"],"summary":"Workflows observed output","description":"Inspect observed output paths and bounded samples from an exact run or recent matching workflow revision.\n\nCLI: `oxygen workflows observed-output`.\n\nMCP: `oxygen_workflow_observed_output`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"run_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"source_hash","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflow_observed_output"],"x-oxygen-cli-command":"oxygen workflows observed-output"}},"/api/cli/workflows/{slug}/runs/{runId}/events":{"get":{"operationId":"workflows.run.events","tags":["Workflows"],"summary":"Workflows runs events","description":"Read the exact Workflow run's bounded event history and whether it is still active.\n\nCLI: `oxygen workflows runs events`.\n\nMCP: `oxygen_workflow_run_events`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflow_run_events"],"x-oxygen-cli-command":"oxygen workflows runs events"}},"/api/cli/workflows/{slug}/runs/{runId}/step-statuses":{"get":{"operationId":"workflows.run.step_statuses","tags":["Workflows"],"summary":"Workflows runs step statuses","description":"Read the current Workflow run status and every step status for immediate execution readback.\n\nCLI: `oxygen workflows runs step-statuses`.\n\nMCP: `oxygen_workflow_run_step_statuses`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflow_run_step_statuses"],"x-oxygen-cli-command":"oxygen workflows runs step-statuses"}},"/api/cli/workflows/{slug}/runs/{runId}/steps":{"get":{"operationId":"workflows.run.steps","tags":["Workflows"],"summary":"Workflows runs steps","description":"Read one Workflow run as its named steps: status, a plain-language outcome per step, timing, credits, the customer-safe failure and bounded input/output.\n\nCLI: `oxygen workflows runs steps`.\n\nMCP: `oxygen_workflow_run_steps`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflow_run_steps"],"x-oxygen-cli-command":"oxygen workflows runs steps"}},"/api/cli/workflows/{slug}/status":{"post":{"operationId":"workflows.resource.status","tags":["Workflows"],"summary":"Workflows status set","description":"Enable or disable a Workflow and record an optional reason. Enabling paid recurring execution requires standing approval and max_credits; CRM-sync workflows use their paired lifecycle instead.\n\nCLI: `oxygen workflows status-set`.\n\nMCP: `oxygen_workflow_resource_status_set`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","disabled"]},"approved":{"type":"boolean"},"max_credits":{"type":"number","minimum":0},"reason":{"type":"string","maxLength":500}},"required":["status"],"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":true,"x-oxygen-spends-credits":true,"x-oxygen-mcp-tools":["oxygen_workflow_resource_status_set"],"x-oxygen-cli-command":"oxygen workflows status-set"}},"/api/cli/workflows/apply":{"post":{"operationId":"postWorkflowsApply","tags":["Workflows"],"summary":"Apply Workflow","description":"Saves a draft or publishes a Workflow. Autonomous tools need standing approval and an explicit or plan-default delivery cap.\n\nMCP: `oxygen_workflows_apply`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Grant this exact revision standing tool authority after review."},"manifest":{"type":"object","description":"Compiled OXYGEN workflow or recipe manifest.","additionalProperties":true},"max_credits":{"type":"number","description":"Optional explicit positive ceiling per autonomous delivery; omit to use the plan-tier default.","exclusiveMinimum":0},"publish":{"type":"boolean","description":"False=draft; default true=publish."},"review":{"type":"boolean","description":"Describe publishing changes without writing."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_apply"]}},"/api/cli/workflows/approvals":{"get":{"operationId":"getWorkflowsApprovals","tags":["Workflows"],"summary":"Workflow Approval Inbox","description":"Lists durable mid-run approvals; defaults to pending.\n\nMCP: `oxygen_workflows_approvals`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum records to return.","minimum":1,"maximum":500}},{"name":"runId","in":"query","required":false,"schema":{}},{"name":"run_id","in":"query","required":false,"schema":{"type":"string","description":"Only approvals for this workflow run id."}},{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter: pending (default), approved, rejected, expired, or all."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflows_approvals"]}},"/api/cli/workflows/call":{"post":{"operationId":"postWorkflowsCall","tags":["Workflows"],"summary":"Call Workflow","description":"Enqueues any workflow without simulating its trigger. live needs approved=true and a positive max_credits cap.\n\nMCP: `oxygen_workflows_call`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required for live calls after inspecting a dry run."},"idempotencyKey":{},"idempotency_key":{"type":"string","description":"Optional idempotency key.","maxLength":300},"input":{"type":"object","description":"Input in every mode, including smoke_test. Default: {}.","additionalProperties":true},"max_credits":{"type":"number","description":"Positive live-call credit ceiling.","minimum":0},"mode":{"type":"string","description":"Execution mode. Use live only with explicit user approval.","enum":["dry_run","live","smoke_test"]},"preview":{"type":"boolean","description":"Describe a live run's effects, accounts, external step count and credit floor without running it. Needs no mode."},"revision_version":{"type":"integer","minimum":1,"description":"Saved revision; historical versions are non-live."},"testNodeId":{},"testScope":{},"test_node_id":{"type":"string","description":"Test one node plus only the predecessors it needs. Non-live, graph workflows only."},"test_scope":{"type":"string","enum":["workflow","node"],"description":"Durable non-live test scope; node requires test_node_id."},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflowId":{},"workflowName":{},"workflow_id":{},"workflow_name":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_call"]}},"/api/cli/workflows/cancel":{"post":{"operationId":"postWorkflowsCancel","tags":["Workflows"],"summary":"Cancel Workflow Run","description":"Cancels a queued or running workflow run.\n\nMCP: `oxygen_workflows_cancel`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"preview":{"type":"boolean","description":"Inspect cancellation impact; cancels nothing."},"runId":{},"run_id":{"type":"string","description":"Run UUID from call.run.id, not runId.","minLength":1,"maxLength":80}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_cancel"]}},"/api/cli/workflows/delete":{"post":{"operationId":"postWorkflowsDelete","tags":["Workflows"],"summary":"Delete Workflow","description":"Previews or permanently deletes one or many workflows. Deletion removes definitions, revisions, triggers, and workflow-scoped budget policies while retaining historical run and usage records. Call once without approved to inspect the impact, then again with approved=true.\n\nMCP: `oxygen_workflows_delete`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Approve the previewed permanent deletion. Defaults to false (preview only)."},"reason":{"type":"string","description":"Optional reason recorded on the deletion.","maxLength":500},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflowId":{},"workflowName":{},"workflow_id":{},"workflow_name":{},"workflows":{"type":"array","description":"Workflow refs for a bulk action.","items":{"type":"string"}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_delete"]}},"/api/cli/workflows/disable":{"post":{"operationId":"postWorkflowsDisable","tags":["Workflows"],"summary":"Disable Workflow","description":"Disables one or many workflows and their triggers. A Table schedule's queued, unstarted runs are canceled.\n\nMCP: `oxygen_workflows_disable`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{},"max_credits":{},"reason":{"type":"string","description":"Audit note for the status change."},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflowId":{},"workflowName":{},"workflow_id":{},"workflow_name":{},"workflows":{"type":"array","description":"Workflow refs for a bulk action.","items":{"type":"string"}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_disable"]}},"/api/cli/workflows/duplicate":{"post":{"operationId":"postWorkflowsDuplicate","tags":["Workflows"],"summary":"Duplicate Workflow","description":"Duplicates a workflow as a disabled copy by default, with new workflow and webhook ids.\n\nMCP: `oxygen_workflows_duplicate`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Copy name; defaults to '<source> Copy'.","minLength":1,"maxLength":200},"newWorkflowId":{},"new_workflow_id":{"type":"string","description":"Optional id for the copy.","minLength":1,"maxLength":160},"status":{"type":"string","description":"Copy status; defaults to disabled.","enum":["active","disabled"]},"triggerId":{},"trigger_id":{"type":"string","description":"Webhook trigger id for duplicated webhook workflows.","minLength":1,"maxLength":160},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflowId":{},"workflowName":{},"workflow_id":{},"workflow_name":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_duplicate"]}},"/api/cli/workflows/enable":{"post":{"operationId":"postWorkflowsEnable","tags":["Workflows"],"summary":"Enable Workflow","description":"Enables one or many workflows. Autonomous tool revisions require approval; provide an explicit per-delivery cap or omit it to use the plan-tier default. Cron responses preview recurring burn and refuse cadences that exceed the plan.\n\nMCP: `oxygen_workflows_enable`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Grant this exact revision standing tool authority after review."},"max_credits":{"type":"number","description":"Optional explicit positive ceiling per autonomous delivery; omit to use the plan-tier default.","exclusiveMinimum":0},"reason":{"type":"string","description":"Audit note for the status change."},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflowId":{},"workflowName":{},"workflow_id":{},"workflow_name":{},"workflows":{"type":"array","description":"Workflow refs for a bulk action.","items":{"type":"string"}}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_enable"]}},"/api/cli/workflows/events/catalog":{"get":{"operationId":"getWorkflowsEventsCatalog","tags":["Workflows"],"summary":"Get Workspace Event","description":"Gets one curated workspace event by exact catalog id and returns a ready-to-copy workflow trigger object.\n\nMCP: `oxygen_workflows_events_get`, `oxygen_workflows_events_list`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"catalog_id","in":"query","required":false,"schema":{"type":"string","description":"Exact curated catalog id returned by oxygen_workflows_events_list.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflows_events_get","oxygen_workflows_events_list"]}},"/api/cli/workflows/events/emit":{"post":{"operationId":"postWorkflowsEventsEmit","tags":["Workflows"],"summary":"Emit Workflow Event","description":"Emits an event to matching workflows. Live requires approval and a positive cap per delivery.\n\nMCP: `oxygen_workflows_events_emit`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required for live event emission after inspecting a dry run."},"event":{"type":"string","description":"Event type, such as email.reply_received.","minLength":1,"maxLength":160},"eventType":{},"event_type":{},"externalEventId":{},"external_event_id":{"type":"string","description":"Optional provider event id.","maxLength":300},"headers":{"type":"object","additionalProperties":true,"description":"Event headers used by workflow matching."},"idempotencyKey":{},"idempotency_key":{"type":"string","description":"Optional explicit event idempotency key.","maxLength":300},"max_credits":{"type":"number","description":"Positive live cap per delivery.","exclusiveMinimum":0},"mode":{"type":"string","description":"Execution mode. Use live only with explicit user approval.","enum":["dry_run","live","smoke_test"]},"payload":{"type":"object","description":"Normalized workflow event payload.","additionalProperties":true},"rawPayload":{},"raw_payload":{},"source":{"type":"string","description":"Event source, such as instantly, calendar, or hubspot.","minLength":1,"maxLength":100}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_events_emit"]}},"/api/cli/workflows/export":{"post":{"operationId":"postWorkflowsExport","tags":["Workflows"],"summary":"Export Workflow Definition","description":"Exports one graph-native workflow as portable editable JSON. Source account UUIDs and trigger authority are removed.\n\nMCP: `oxygen_workflows_export`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflowId":{},"workflow_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_export"]}},"/api/cli/workflows/failures":{"get":{"operationId":"getWorkflowsFailures","tags":["Workflows"],"summary":"List Workflow Failures","description":"Lists failed workflow runs and trigger scheduler failures for the organization. Durable recipe bundles are omitted unless include_bundle is true.\n\nMCP: `oxygen_workflows_failures`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"includeBundle","in":"query","required":false,"schema":{}},{"name":"include_bundle","in":"query","required":false,"schema":{"type":"boolean","description":"Include durable recipe bundles in the response. Defaults to false."}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflows_failures"]}},"/api/cli/workflows/get":{"post":{"operationId":"postWorkflowsGet","tags":["Workflows"],"summary":"Get Workflow","description":"Gets a workflow automation definition and current manifest. A cron the plan slows carries trigger.slowedToPlanMinimum; a webhook trigger's rate_limit is the deliveries a minute its URL accepts on this plan.\n\nMCP: `oxygen_workflows_get`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflowId":{},"workflowName":{},"workflow_id":{},"workflow_name":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_get"]}},"/api/cli/workflows/import":{"post":{"operationId":"postWorkflowsImport","tags":["Workflows"],"summary":"Import Workflow Definition","description":"Creates a new current but disabled workflow from a portable graph definition. Never overwrites or enables a workflow.\n\nMCP: `oxygen_workflows_import`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionBindings":{},"connection_bindings":{"type":"object","description":"Artifact binding_id -> active destination connection UUID.","additionalProperties":{"type":"string"}},"definition":{"type":"object","description":"Portable oxygen-workflow-definition envelope returned by oxygen_workflows_export.","additionalProperties":true},"webhook_trigger_id":{"type":"string","description":"Optional destination webhook trigger id."},"workflow_id":{"type":"string","description":"Optional destination workflow id."},"workflow_name":{"type":"string","description":"Optional destination display name."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_import"]}},"/api/cli/workflows/import/preflight":{"post":{"operationId":"postWorkflowsImportPreflight","tags":["Workflows"],"summary":"Preflight Workflow Definition Import","description":"Checks create-only workflow id and exact destination account bindings without creating anything.\n\nMCP: `oxygen_workflows_import_preflight`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionBindings":{},"connection_bindings":{"type":"object","description":"Artifact binding_id -> active destination connection UUID.","additionalProperties":{"type":"string"}},"definition":{"type":"object","description":"Portable oxygen-workflow-definition envelope returned by oxygen_workflows_export.","additionalProperties":true},"webhook_trigger_id":{},"workflow_id":{"type":"string","description":"Optional destination workflow id."},"workflow_name":{"type":"string","description":"Optional destination display name."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_import_preflight"]}},"/api/cli/workflows/lint":{"post":{"operationId":"postWorkflowsLint","tags":["Workflows"],"summary":"Lint Workflow","description":"Validate draft/publish readiness without saving, running, or spending.\n\nMCP: `oxygen_workflows_lint`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Candidate authority only."},"manifest":{"type":"object","description":"Compiled OXYGEN workflow or recipe manifest.","additionalProperties":true},"max_credits":{"type":"number","exclusiveMinimum":0,"description":"Candidate delivery cap."},"phase":{"type":"string","enum":["draft","publish"],"description":"Default: publish."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_lint"]}},"/api/cli/workflows/mcp":{"post":{"operationId":"postWorkflowsMcp","tags":["Workflows"],"summary":"Publish Workflow as MCP Tool","description":"Publishes an active workflow as a dynamic MCP tool; approval and spend gates remain unchanged.\n\nMCP: `oxygen_workflows_mcp_disable`, `oxygen_workflows_mcp_enable`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string","description":"Description for the published MCP tool.","maxLength":1000},"display_name":{"type":"string","description":"Display name for the published MCP tool.","maxLength":200},"enabled":{},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflow_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_mcp_disable","oxygen_workflows_mcp_enable"]}},"/api/cli/workflows/mcp-callable":{"get":{"operationId":"workflows.mcp_callable","tags":["Workflows"],"summary":"Workflows MCP list","description":"List this workspace's published MCP-callable Workflow definitions and interfaces.\n\nMCP: `oxygen_workflows_mcp_callable`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflows_mcp_callable"]}},"/api/cli/workflows/rename":{"post":{"operationId":"postWorkflowsRename","tags":["Workflows"],"summary":"Rename Workflow","description":"Renames only the display label; the next apply may overwrite it from the manifest.\n\nMCP: `oxygen_workflows_rename`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"New display name for the workflow.","minLength":1,"maxLength":200},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflowId":{},"workflowName":{},"workflow_id":{},"workflow_name":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_rename"]}},"/api/cli/workflows/resume":{"post":{"operationId":"postWorkflowsResume","tags":["Workflows"],"summary":"Resume Workflow (Approve/Reject)","description":"Approves or rejects a paused run. Pass its plan_hash to bind the decision to the reviewed plan; the run's cap remains enforced.\n\nMCP: `oxygen_workflows_resume`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","description":"approve or reject."},"planHash":{},"plan_hash":{"type":"string","description":"Reviewed plan hash from the approval inbox."},"runId":{},"run_id":{"type":"string","description":"Run UUID from call.run.id, not runId.","minLength":1,"maxLength":80},"stepId":{},"step_id":{"type":"string","description":"Approval step id, if ambiguous."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_resume"]}},"/api/cli/workflows/retry":{"post":{"operationId":"postWorkflowsRetry","tags":["Workflows"],"summary":"Retry Failed Workflow Run","description":"Previews a failed-run resume from its first failed step. Preserves completed work and refuses uncertain writes. approved=true executes; live needs a new positive cap.\n\nMCP: `oxygen_workflows_retry`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Execute the previewed retry; false previews only."},"max_credits":{"type":"number","description":"Required new positive credit ceiling when retrying a live run.","exclusiveMinimum":0},"runId":{},"run_id":{"type":"string","description":"Run UUID from call.run.id, not runId.","minLength":1,"maxLength":80}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_retry"]}},"/api/cli/workflows/revisions":{"get":{"operationId":"getWorkflowsRevisions","tags":["Workflows"],"summary":"Workflow Version History","description":"Every published version of one workflow, newest first: version, source hash, compiler version, publisher, and which one runs now (`isCurrent`). Each apply or canvas save cuts a revision — use this to find the version to restore. include_manifest=true returns each manifest.\n\nMCP: `oxygen_workflows_revisions`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"number","description":"Max revisions. Default 50, max 200."}},{"name":"workflow","in":"query","required":false,"schema":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400}},{"name":"workflow_id","in":"query","required":false,"schema":{}},{"name":"workflow_name","in":"query","required":false,"schema":{}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflows_revisions"]}},"/api/cli/workflows/revisions/restore":{"post":{"operationId":"postWorkflowsRevisionsRestore","tags":["Workflows"],"summary":"Restore Workflow Version","description":"Republish an earlier version as a new revision. Restore stays append-only and reruns lint, effect, cadence, authority, and spend-cap gates.\n\nMCP: `oxygen_workflows_revisions_restore`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Required to re-arm an autonomous tool workflow."},"max_credits":{"type":"number","description":"Per-delivery ceiling; omit for the plan default."},"version":{"type":"number","description":"Revision version to re-publish."},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflow_id":{},"workflow_name":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflows_revisions_restore"]}},"/api/cli/workflows/run":{"post":{"operationId":"postWorkflowsRun","tags":["Workflows"],"summary":"Get Workflow Run","description":"Gets one workflow run with step state, outputs, events, and worker claim identity.\n\nMCP: `oxygen_workflows_run`, `oxygen_workflows_tail`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"runId":{},"run_id":{"type":"string","description":"Run UUID from call.run.id, not runId.","minLength":1,"maxLength":80}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_run","oxygen_workflows_tail"]}},"/api/cli/workflows/runs":{"get":{"operationId":"getWorkflowsRuns","tags":["Workflows"],"summary":"List Workflow Runs","description":"Stored runs newest first; default 50. Filter mode/status, echo nextCursor with the same filters. summary lists complete references; exact run_id + value reads long public payloads losslessly. Internal faults stay collapsed.\n\nMCP: `oxygen_workflows_runs`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"none","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflows_runs"]}},"/api/cli/workflows/schema":{"get":{"operationId":"getWorkflowsSchema","tags":["Workflows"],"summary":"Workflow Schema","description":"Returns the JSON schema for OXYGEN workflow manifests and API calls.\n\nMCP: `oxygen_workflows_schema`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"subject","in":"query","required":false,"schema":{"type":"string","description":"graph: canonical v2 authoring; manifest: legacy v1; definition: portable export.","enum":["all","apply","call","event","trigger","manifest","graph","definition"]}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflows_schema"]}},"/api/cli/workflows/tags":{"post":{"operationId":"postWorkflowsTags","tags":["Workflows"],"summary":"Tag Workflow","description":"Replaces a workflow's tag set; [] clears it. Does not create a revision.\n\nMCP: `oxygen_workflows_tag`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{},"tags":{"type":"array","items":{"type":"string"},"description":"The workflow's new tag set."},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflow_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflows_tag"]}},"/api/cli/workflows/templates/run":{"post":{"operationId":"postWorkflowsTemplatesRun","tags":["Workflows"],"summary":"Run Workflow Template (removed)","description":"Removed alias (HTTP 410). Use oxygen_blueprints_apply, then oxygen_workflows_call.\n\nMCP: `oxygen_workflow_templates_run`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Must be true for live template runs with side effects."},"input":{"type":"object","description":"Workflow template input object.","additionalProperties":true},"mode":{"type":"string","description":"Execution mode. Use live only with explicit user approval.","enum":["dry_run","live","smoke_test"]},"template_id":{"type":"string","description":"Workflow template id.","minLength":1,"maxLength":120},"workflow_id":{"type":"string","description":"Workflow id to create or update.","maxLength":160},"workflow_name":{"type":"string","description":"Workflow display name.","maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflow_templates_run"]}},"/api/cli/workflows/tool-output-paths":{"get":{"operationId":"workflows.tool_output_paths","tags":["Workflows"],"summary":"Workflows tool output paths","description":"Discover bounded workspace-observed tool output paths and run/revision provenance, without exposing provider values.\n\nCLI: `oxygen workflows tool-output-paths`.\n\nMCP: `oxygen_workflow_tool_output_paths`.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"tool_id","in":"query","required":true,"schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"contract","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflow_tool_output_paths"],"x-oxygen-cli-command":"oxygen workflows tool-output-paths"}},"/api/cli/workflows/webhooks/deliveries":{"get":{"operationId":"getWorkflowsWebhooksDeliveries","tags":["Workflows"],"summary":"Webhook Deliveries","description":"Lists webhook payloads, safe headers, auth outcomes, and started runs. rejected=auth failed; blocked=authenticated/no run; ran=run started. Filter by trigger, workflow, or outcome. Sensitive headers are omitted.\n\nMCP: `oxygen_workflow_webhook_deliveries`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Result limit, 1-200; default 50.","minimum":1,"maximum":200}},{"name":"outcome","in":"query","required":false,"schema":{"type":"string","description":"Delivery outcome filter.","enum":["rejected","blocked","ran"]}},{"name":"trigger","in":"query","required":false,"schema":{}},{"name":"triggerId","in":"query","required":false,"schema":{}},{"name":"trigger_id","in":"query","required":false,"schema":{"type":"string","description":"Exact webhook trigger name.","minLength":1,"maxLength":200}},{"name":"workflowId","in":"query","required":false,"schema":{}},{"name":"workflow_id","in":"query","required":false,"schema":{"type":"string","description":"Workflow UUID filter.","minLength":1,"maxLength":200}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workflow_webhook_deliveries"]}},"/api/cli/workflows/webhooks/deliveries/replay":{"post":{"operationId":"postWorkflowsWebhooksDeliveriesReplay","tags":["Workflows"],"summary":"Replay Webhook","description":"Durable inspectable dry_run of a verified outcome=ran delivery's exact revision/payload. No resend, original change, delivery-row append, credits, paid calls, or writes; internal reads/GETs may run. Same delivery/request_key returns its run. IDs: oxygen_workflow_webhook_deliveries.\n\nMCP: `oxygen_workflow_webhook_delivery_replay`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"deliveryId":{},"delivery_id":{"type":"string","description":"outcome=ran delivery UUID.","minLength":1,"maxLength":80},"requestKey":{},"request_key":{"type":"string","description":"Defaults to MCP request id.","minLength":1,"maxLength":200}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-mcp-tools":["oxygen_workflow_webhook_delivery_replay"]}},"/api/cli/workflows/webhooks/rotate":{"post":{"operationId":"postWorkflowsWebhooksRotate","tags":["Workflows"],"summary":"Rotate Webhook Secret","description":"Previews or rotates the current published webhook secret. Call without approved first; approved=true invalidates the old secret and returns the replacement once.\n\nMCP: `oxygen_workflow_webhook_rotate`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"Confirm rotation after reviewing the preview."},"workflow":{"type":"string","description":"Workflow id, slug, exact name, or copied workflow URL.","minLength":1,"maxLength":400},"workflowId":{},"workflow_id":{}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workflow_webhook_rotate"]}},"/api/cli/workspace/infrastructure/exit":{"post":{"operationId":"postWorkspaceInfrastructureExit","tags":["Workspace"],"summary":"End Workspace Infrastructure","description":"Preview all external infrastructure belonging to this workspace and, after explicit user confirmation, stop its renewals and begin teardown through already paid terms. A paid plan ending alone does not authorize this action. First call without approved=true; show the exact resources and consequences to the user. Never fill confirm_workspace or plan_hash yourself before the user confirms the preview. Free, 0 credits.\n\nMCP: `oxygen_workspace_infrastructure_exit`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean","description":"True only after the user approves the preview."},"confirm_workspace":{"type":"string","description":"Exact workspace slug or ID from the preview, supplied after user confirmation."},"plan_hash":{"type":"string","description":"Fresh plan_hash from the preview."}},"additionalProperties":true}}}},"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":true,"x-oxygen-destructive":true,"x-oxygen-mcp-tools":["oxygen_workspace_infrastructure_exit"]}},"/api/cli/workspace/map":{"get":{"operationId":"getWorkspaceMap","tags":["Workspace"],"summary":"Workspace Map","description":"What THIS workspace actually contains, by primitive: the newest tables, CRM objects, sequences, workflows, agents, wiki pages, posts and projects, each with its id, name, last activity, tags and deep-link, plus the person's Oxygents, group chats and Copilot chats where the Copilot is theirs. Capability search tells you what OXYGEN can do; this tells you what is here, which is the half you otherwise have to guess. Filter with `kind`, `tag` (delegated to the Tags footprint read, so it spans primitives this map does not model), or `query` (name, slug or tag; it also searches CRM records and inbox conversations). A kind asked for by name that this caller cannot read comes back empty and is named in `unavailable` with why. Read-only, 0 credits — and read-only literally: it creates nothing in order to answer, so a workspace with no wiki pages reports zero rather than a starter set this call seeded. Bounded on purpose: each kind returns its newest few objects under a character budget the payload echoes back as `budget`, and `capped` on a kind means its `matched` count is a floor rather than a total. `degraded` names any primitive whose read failed, so an empty kind is never mistaken for a workspace that holds nothing. Hydrate one object with its own primitive's exact read.\n\nMCP: `oxygen_workspace_map`.\n\nFields are inferred from the route and its callers; types and requirements may be incomplete.","parameters":[{"$ref":"#/components/parameters/ClientVersion"},{"name":"kind","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated kinds to include: table, crm_object, sequence, workflow, agent, knowledge_page, post, project, oxygent, oxygent_group, copilot_chat, record, conversation. Omit for every kind this caller can read; record and conversation need `query` or `tag`.","maxLength":200}},{"name":"query","in":"query","required":false,"schema":{"type":"string","description":"Case-insensitive match on name, slug, or tag; records and conversations by their own searches.","maxLength":200}},{"name":"tag","in":"query","required":false,"schema":{"type":"string","description":"Only objects carrying this workspace tag. Answered by the Tags per-tag footprint read.","maxLength":100}}],"responses":{"200":{"$ref":"#/components/responses/Success"},"default":{"$ref":"#/components/responses/Error"}},"x-oxygen-schema-source":"inferred","x-oxygen-writes":false,"x-oxygen-mcp-tools":["oxygen_workspace_map"]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A workspace API key from Settings → CLI and MCP, or `oxygen api-keys create`."}},"parameters":{"ClientVersion":{"name":"X-Oxygen-Client-Version","in":"header","required":true,"description":"Required with an API key: a version at or above `meta.minimum_cli_version` (currently 1.1011.489). A missing or older value is refused with 426 `cli_update_required`.","schema":{"type":"string","example":"1.1011.489"}}},"schemas":{"Success":{"type":"object","required":["ok","data","meta"],"properties":{"ok":{"const":true},"data":{"type":"object","description":"The operation's result; see the operation's description."},"meta":{"type":"object","properties":{"command":{"type":"string","description":"The operation that answered."},"version":{"type":"string","description":"The API version that answered.","example":"1.1026.33"},"minimum_cli_version":{"type":"string","description":"The lowest X-Oxygen-Client-Version accepted.","example":"1.1011.489"}}}}},"Error":{"type":"object","required":["ok","error","meta"],"properties":{"ok":{"const":false},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable code. Branch on this.","example":"invalid_request"},"message":{"type":"string","description":"A sentence you can show a person.","example":"limit must be at most 1000."},"details":{"type":"object","additionalProperties":true,"description":"Recovery data, e.g. next_step or retry_after_seconds."}}},"meta":{"type":"object","properties":{"command":{"type":"string","description":"The operation that answered."},"version":{"type":"string","description":"The API version that answered.","example":"1.1026.33"},"minimum_cli_version":{"type":"string","description":"The lowest X-Oxygen-Client-Version accepted.","example":"1.1011.489"}}}}}},"responses":{"Success":{"description":"Accepted. A state-changing response reports `effect_outcome` and `changed` in `data`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"Error":{"description":"Refused or failed. Branch on `error.code`; `error.details.next_step` names the recovery.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
