Files
zeekay bc4ddf332b chore: rebase the tree onto upstream master fa1a9a60
Mechanically re-derived: bin/debrand runs over a fresh import of
posthog/posthog@fa1a9a60d4 (2026-08-06).
The pipeline (.hanzo/workflows), the Dockerfiles and bin/docker*
entrypoints, compose files, LLM.md and the squashed initial migration
are restored from the shipped tree, same as the previous import.

The prune's import-closure guard kept 21 products the new core now
imports; dropping them is a refactor now, recorded rather than forced.
2026-08-06 01:25:36 -07:00

1574 lines
85 KiB
JSON

{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AIObservabilityGetCostsSchema": {
"type": "object",
"properties": {
"projectId": {
"description": "Project ID. Defaults to the active project when omitted.",
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"days": {
"type": "number"
}
}
},
"BusinessKnowledgeUrlSourceCreateSchema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"maxLength": 255,
"description": "Short human label for the source. Shown in the settings list and in agent citations."
},
"url": {
"type": "string",
"maxLength": 2048,
"format": "uri",
"description": "Public HTTP(S) URL to fetch. Private or internal hosts are rejected."
},
"source_type": {
"default": "url",
"description": "Source type. Always \"url\" for this tool.",
"type": "string",
"const": "url"
},
"refresh_interval": {
"default": "manual",
"description": "How often to auto-refresh this source in the background. Defaults to \"manual\" (no auto-refresh).",
"type": "string",
"enum": ["manual", "1h", "6h", "24h", "7d"]
},
"always_include": {
"default": false,
"description": "When true, this source's content is injected into every support reply prompt as general context (tone, policies, direction), not just when it matches a query.",
"type": "boolean"
}
},
"required": ["name", "url"]
},
"DebugMcpUiAppsSchema": {
"type": "object",
"properties": {
"message": {
"description": "Optional message to include in the debug data",
"type": "string"
}
}
},
"EmailTemplateDesignPatchSchema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The email template id to edit."
},
"operations": {
"minItems": 1,
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "update_content"
},
"id": {
"type": "string",
"description": "Id of the content block to update."
},
"patch": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Partial content-block fields, deep-merged into the existing block; a null leaf deletes that key. e.g. {values: {text: '<p>Hi</p>'}} changes only the block's text."
}
},
"required": ["op", "id", "patch"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "update_column"
},
"id": {
"type": "string",
"description": "Id of the column to update."
},
"patch": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Partial column fields, deep-merged; a null leaf deletes that key."
}
},
"required": ["op", "id", "patch"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "update_row"
},
"id": {
"type": "string",
"description": "Id of the row to update."
},
"patch": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Partial row fields, deep-merged; a null leaf deletes that key."
}
},
"required": ["op", "id", "patch"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "update_body"
},
"patch": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Partial body fields, deep-merged. e.g. {values: {backgroundColor: '#ffffff'}}."
}
},
"required": ["op", "patch"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "add_content"
},
"column_id": {
"type": "string",
"description": "Id of the column to insert the block into."
},
"content": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "A content block {type, values: {...}}; omit id and values._meta — they are assigned server-side. type is one of text, heading, button, image, divider, html, etc."
},
"index": {
"description": "0-based insert position; omit to append to the end.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": ["op", "column_id", "content"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "remove_content"
},
"id": {
"type": "string",
"description": "Id of the content block to remove."
}
},
"required": ["op", "id"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "move_content"
},
"id": {
"type": "string",
"description": "Id of the content block to move."
},
"column_id": {
"type": "string",
"description": "Id of the destination column."
},
"index": {
"description": "0-based position in the destination column; omit to append.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": ["op", "id", "column_id"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "add_row"
},
"row": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "A full row {cells, columns: [{contents: [...], values}], values}; ids and Unlayer numbering are assigned server-side for the row and everything nested in it."
},
"index": {
"description": "0-based insert position; omit to append to the end.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": ["op", "row"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "remove_row"
},
"id": {
"type": "string",
"description": "Id of the row to remove."
}
},
"required": ["op", "id"]
}
]
},
"description": "Ordered edits applied atomically to the template's Unlayer design: the stored design is read, the ops are applied in order, the result is validated and re-rendered to HTML, and saved only if valid — otherwise the template is left unchanged. Reference blocks by id so you never resend the whole design."
}
},
"required": ["id", "operations"]
},
"EventDefinitionUpdateInputSchema": {
"type": "object",
"properties": {
"description": {
"description": "Description explaining when the event is triggered",
"type": "string"
},
"tags": {
"description": "Tags to organize events by product area (e.g. \"checkout\", \"onboarding\") or user journey stage (e.g. \"acquisition\", \"activation\", \"monetization\", \"retention\")",
"type": "array",
"items": {
"type": "string"
}
},
"verified": {
"description": "Mark as verified to indicate the event is properly instrumented and tracking correctly",
"type": "boolean"
},
"hidden": {
"description": "Mark event as no longer used/captured. Hides it from UI while preserving historical data",
"type": "boolean"
}
}
},
"EventDefinitionUpdateSchema": {
"type": "object",
"properties": {
"eventName": {
"type": "string",
"description": "The name of the event to update (e.g. \"$pageview\", \"user_signed_up\")"
},
"data": {
"type": "object",
"properties": {
"description": {
"description": "Description explaining when the event is triggered",
"type": "string"
},
"tags": {
"description": "Tags to organize events by product area (e.g. \"checkout\", \"onboarding\") or user journey stage (e.g. \"acquisition\", \"activation\", \"monetization\", \"retention\")",
"type": "array",
"items": {
"type": "string"
}
},
"verified": {
"description": "Mark as verified to indicate the event is properly instrumented and tracking correctly",
"type": "boolean"
},
"hidden": {
"description": "Mark event as no longer used/captured. Hides it from UI while preserving historical data",
"type": "boolean"
}
},
"description": "The event definition data to update"
}
},
"required": ["eventName", "data"]
},
"ExecuteSQLSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"minLength": 1,
"description": "The final SQL query to be executed."
},
"truncate": {
"default": true,
"description": "Whether to truncate large blob/JSON values in results. Defaults to true. Set to false when you need full untruncated results (e.g., for dumping to a file).",
"type": "boolean"
},
"connectionId": {
"description": "Optional id of an external data source (e.g. a Postgres, DuckDB, or MySQL direct-query connection). When set, runs the query against that source instead of the Datastore catalog. Use external-data-sources-list to discover available connection ids.",
"type": "string"
}
},
"required": ["query"]
},
"ExperimentResultsGetSchema": {
"type": "object",
"properties": {
"id": {
"type": "number",
"description": "The ID of the experiment to get comprehensive results for"
},
"refresh": {
"default": false,
"description": "Force refresh of results instead of using cached values. Defaults to false.",
"type": "boolean"
}
},
"required": ["id"]
},
"ExternalDataJobsAfterSchema": {
"type": "string",
"description": "ISO timestamp — only return jobs created after this date (e.g. \"2025-01-01T00:00:00Z\")."
},
"ExternalDataJobsBeforeSchema": {
"type": "string",
"description": "ISO timestamp — only return jobs created before this date (e.g. \"2025-12-31T23:59:59Z\")."
},
"ExternalDataJobsSchemasSchema": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filter jobs by table schema names (e.g. [\"users\", \"orders\"]). Only returns jobs for these tables."
},
"ExternalDataSourcePayloadSchema": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Connection credentials for the source. Keys depend on source_type. For database sources: host, port, database, user, password, schema. For SaaS sources: api_key or OAuth fields. For source_type \"Custom\" (a user-defined REST API): `manifest_json` (a stringified RESTAPIConfig describing client.base_url, auth, and resources) plus the credential for the auth type declared in the manifest — `auth_token` (bearer), `auth_api_key` (api_key), or `auth_password` (http_basic); keep secrets in these auth_* keys, never inline in manifest_json. Use external-data-sources-wizard (pass source_type) to see required fields per source type. For the advanced external-data-sources-create flow, the per-table 'schemas' array (built from external-data-sources-db-schema) also goes in here, e.g. {\"host\": ..., \"password\": ..., \"schemas\": [{\"name\": \"orders\", \"should_sync\": true, \"sync_type\": \"incremental\", \"incremental_field\": \"updated_at\", \"incremental_field_type\": \"datetime\"}]}. Do not pass unresolved {\"secretRef\": ...} objects — resolve secrets to real values first, or use a credential_id from data-warehouse-source-connect-link."
},
"ExternalDataSourceTypeSchema": {
"type": "string",
"description": "The source type name (e.g. \"Postgres\", \"MySQL\", \"Stripe\"). Use external-data-sources-wizard to see available types and their required fields."
},
"FeedbackSubmitSchema": {
"type": "object",
"properties": {
"summary": {
"type": "string",
"minLength": 1,
"description": "A one-sentence headline capturing the feedback (e.g. \"session replay scrubber jumps backwards when you click the timeline\", \"query-trends descriptions made it hard to choose between trends and funnels\", or \"the new SQL editor autocomplete is excellent\")."
},
"feedback_type": {
"type": "string",
"enum": ["product", "mcp", "docs", "scout", "other"],
"description": "What this feedback is about. \"product\" = any Insights product or feature (insights, session replay, feature flags, the data warehouse, web analytics, error tracking, etc.). \"mcp\" = this MCP server itself — a tool, its input schema, response format, an error, or these instructions. \"docs\" = Insights documentation. \"scout\" = a canonical Insights scout skill's content — reserved for scheduled scout runs reporting an improvement opportunity in their own Insights-authored skill (set `scout_skill_name`, `scout_skill_version`, and `scout_category`). \"other\" = anything that doesn't fit the above."
},
"sentiment": {
"type": "string",
"enum": ["positive", "neutral", "negative", "mixed"],
"description": "The overall tone. Use \"negative\" for something broken or blocking, \"mixed\" for mostly-fine-but-with-a-concrete-problem, \"neutral\" for a suggestion or feature request with no strong sentiment, and \"positive\" for praise or something that worked well. All sentiments are welcome — positive feedback is encouraged, not just problems."
},
"product_area": {
"description": "The Insights product or area this is about, in free text (e.g. \"session replay\", \"insights\", \"data warehouse\", \"feature flags\", \"docs\"). Most useful for product feedback; for MCP feedback the tool name belongs in `details`/`friction_points` instead.",
"type": "string"
},
"category": {
"description": "For MCP feedback (`feedback_type: \"mcp\"`) only: the single category that best describes the dominant theme. Pick \"missing_tool\" if a capability was absent, \"tool_description\" if the tool docs were unclear, \"tool_input_schema\" if input args were confusing, \"tool_output_format\" if the response was hard to consume, \"instructions_clarity\" if these MCP instructions were unclear, \"tool_correctness\" if a tool returned wrong data, \"error_message\" if an error was unhelpful, \"performance\" if latency was the issue. Omit for product, docs, or other feedback.",
"type": "string",
"enum": [
"tool_correctness",
"tool_description",
"tool_input_schema",
"tool_output_format",
"missing_tool",
"instructions_clarity",
"performance",
"error_message",
"other"
]
},
"scout_skill_name": {
"description": "For scout feedback (`feedback_type: \"scout\"`) only: the canonical scout skill the feedback is about (e.g. \"signals-scout-web-analytics\"), exactly as named in the run identity. Required for scout feedback — without it the feedback cannot be aggregated per skill.",
"type": "string"
},
"scout_skill_version": {
"description": "For scout feedback (`feedback_type: \"scout\"`) only: the skill version the run executed (from the run identity). Feedback is only actionable against the version that produced it — the skill may have moved since.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"scout_category": {
"description": "For scout feedback (`feedback_type: \"scout\"`) only: the single category that best describes the skill gap. \"false_positive\" = the skill's detection rules surfaced something that wasn't real; \"missed_detection\" = a real issue the skill's instructions steered you past; \"discriminator_gap\" = the skill's signal-vs-baseline discriminator doesn't hold for a class of projects; \"wasted_investigation\" = an investigation pattern the skill mandates burned budget without payoff; \"instruction_ambiguity\" = an instruction that is ambiguous in practice. Omit for non-scout feedback.",
"type": "string",
"enum": [
"false_positive",
"missed_detection",
"discriminator_gap",
"wasted_investigation",
"instruction_ambiguity",
"other"
]
},
"task_completed": {
"description": "Were you able to complete the user's task? Be honest — \"false\" is just as useful as \"true\". Most relevant when `feedback_type` is \"mcp\".",
"type": "boolean"
},
"tools_used": {
"description": "The MCP tool names you called while working on the user's task (e.g. [\"read-data-schema\", \"query-trends\"]). Helps us correlate feedback to specific tools.",
"type": "array",
"items": {
"type": "string"
}
},
"friction_points": {
"description": "Clear, concise bullet points describing the friction — what was confusing, broken, slow, or missing. Quote the exact product surface, tool name, parameter, or error text where you can. Omit for purely positive feedback.",
"type": "string"
},
"suggested_improvement": {
"description": "The single most impactful, concrete change that would address this feedback, if you can name one (e.g. \"add a `filters` example to query-funnel's description\", or \"let the replay scrubber snap to the nearest event\"). Optional — praise or an observation doesn't need one.",
"type": "string"
},
"user_request": {
"description": "A short, anonymised paraphrase of what the user originally asked you to do. Do not include PII, customer names, or sensitive query content.",
"type": "string"
},
"details": {
"description": "Any additional context that doesn't fit the other fields. Keep it to clear, concise bullet points.",
"type": "string"
}
},
"required": ["summary", "feedback_type", "sentiment"]
},
"InsightQueryInputSchema": {
"type": "object",
"properties": {
"insightId": {
"description": "The insight to run: its numeric `id` or 8-character `short_id`.",
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"output_format": {
"default": "optimized",
"description": "Output format. \"optimized\" returns a human-readable summary from server-side formatters (recommended for analysis). \"json\" returns the raw query results as JSON.",
"type": "string",
"enum": ["optimized", "json"]
},
"variables_override": {
"description": "Object (or pre-encoded JSON string) to override the insight's InsightsQL variables for this run only (not persisted). Format: {\"<variable_id>\": {\"code_name\": \"<code_name>\", \"variableId\": \"<variable_id>\", \"value\": <new_value>}}. Each entry must include `code_name` — partial entries are silently dropped. The simplest workflow is to call `insight-get` first, copy the matching entry from the response's query variables, and mutate `value`. Top-level keys replace; nested values are not deep-merged. Ignored when accessed via a sharing token.",
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
}
]
},
"filters_override": {
"description": "Object (or pre-encoded JSON string) to override the insight's filters for this run only (not persisted). Top-level keys replace; nested values are not deep-merged — pass the complete value for any key you override. Accepts the same keys as the dashboard filters schema (e.g., `date_from`, `date_to`, `properties`). Ignored when accessed via a sharing token.",
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
}
]
}
},
"required": ["insightId"]
},
"OrganizationGetAllSchema": {
"type": "object",
"properties": {}
},
"OrganizationSetActiveSchema": {
"anyOf": [
{
"type": "object",
"properties": {
"orgId": {
"type": "string",
"description": "The organization to switch to: the `id` returned by `organizations-get` (a UUID-like string, not the organization name). Use `organizations-get` to resolve a name to its id."
}
},
"required": ["orgId"]
},
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Alias for `orgId`. Accepts the `id` returned by `organizations-list` / `organization-get`."
}
},
"required": ["id"]
},
{
"type": "object",
"properties": {
"organizationId": {
"type": "string",
"description": "Alias for `orgId`. Accepts the `id` returned by `organizations-list` / `organization-get`."
}
},
"required": ["organizationId"]
},
{
"type": "object",
"properties": {
"organization_id": {
"type": "string",
"description": "Alias for `orgId`. Accepts the `id` returned by `organizations-list` / `organization-get`."
}
},
"required": ["organization_id"]
},
{
"type": "object",
"properties": {
"org_id": {
"type": "string",
"description": "Alias for `orgId`. Accepts the `id` returned by `organizations-list` / `organization-get`."
}
},
"required": ["org_id"]
}
]
},
"PathCleaningRulesUpdateSchema": {
"type": "object",
"properties": {
"operations": {
"minItems": 1,
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"action": {
"type": "string",
"const": "append"
},
"alias": {
"type": "string",
"description": "The human-readable replacement, e.g. \"/users/<id>/profile\". Use angle-bracket placeholders (<id>, <uuid>, <slug>) by convention. An empty string is valid — it deletes the matched text (e.g. to strip a \"?page=N\" fragment). Not a regex template — backreferences are not supported."
},
"regex": {
"type": "string",
"minLength": 1,
"description": "A re2 pattern matched against the path, e.g. \"/users/\\\\d+/profile\". No need to escape \"/\". Anchor with ^ / $ when you mean it."
}
},
"required": ["action", "alias", "regex"],
"description": "Add a new rule at the end of the ordered list (runs last)."
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
"const": "insert"
},
"index": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "Zero-based position to insert the rule at. Existing rules shift down."
},
"alias": {
"type": "string",
"description": "The human-readable replacement, e.g. \"/users/<id>/profile\". Use angle-bracket placeholders (<id>, <uuid>, <slug>) by convention. An empty string is valid — it deletes the matched text (e.g. to strip a \"?page=N\" fragment). Not a regex template — backreferences are not supported."
},
"regex": {
"type": "string",
"minLength": 1,
"description": "A re2 pattern matched against the path, e.g. \"/users/\\\\d+/profile\". No need to escape \"/\". Anchor with ^ / $ when you mean it."
}
},
"required": ["action", "index", "alias", "regex"],
"description": "Insert a new rule at a specific position — use when it must run before more general rules."
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
"const": "replace"
},
"target_alias": {
"type": "string",
"description": "The alias of the existing rule to target (must match an existing rule exactly). Use \"\" to target a rule whose alias is empty."
},
"alias": {
"description": "New alias. Omit to keep the current alias.",
"type": "string"
},
"regex": {
"description": "New regex. Omit to keep the current regex.",
"type": "string",
"minLength": 1
}
},
"required": ["action", "target_alias"],
"description": "Replace the alias and/or regex of an existing rule, keeping its position."
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
"const": "remove"
},
"target_alias": {
"type": "string",
"description": "The alias of the existing rule to target (must match an existing rule exactly). Use \"\" to target a rule whose alias is empty."
}
},
"required": ["action", "target_alias"],
"description": "Remove an existing rule by alias."
},
{
"type": "object",
"properties": {
"action": {
"type": "string",
"const": "reorder"
},
"ordered_aliases": {
"type": "array",
"items": {
"type": "string"
},
"description": "The full set of current aliases in the new desired order (including \"\" for any empty-alias rule and any duplicates). Must be a permutation of the existing aliases."
}
},
"required": ["action", "ordered_aliases"],
"description": "Reorder the existing rules. Order matters: rules apply sequentially, each feeding the next."
}
]
},
"description": "Ordered list of edits to apply to the current path cleaning rules, in sequence."
},
"sample_paths": {
"description": "Optional real paths (e.g. \"/users/123/profile\") to preview against, up to 25. The response shows how the resulting rule set rewrites each one. Approximate (JS regex, not re2) — use execute-sql with replaceRegexpAll to confirm edge cases.",
"maxItems": 25,
"type": "array",
"items": {
"type": "string",
"maxLength": 2048
}
},
"confirm": {
"default": false,
"description": "Must be true to persist. When false (default) the tool returns a preview of the resulting rules (and any sample-path rewrites) WITHOUT saving — surface it to the user, then re-run with confirm:true.",
"type": "boolean"
}
},
"required": ["operations"]
},
"ProjectGetAllSchema": {
"type": "object",
"properties": {}
},
"ProjectSetActiveSchema": {
"type": "object",
"properties": {
"projectId": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
}
},
"required": ["projectId"]
},
"PromptListInputSchema": {
"type": "object",
"properties": {
"search": {
"description": "Optional substring filter applied to prompt names and prompt content.",
"type": "string"
},
"content": {
"default": "none",
"description": "Controls how much prompt content is included in list results. 'full' includes the full prompt, 'preview' includes a short prompt_preview, and 'none' omits prompt content entirely.",
"type": "string",
"enum": ["full", "preview", "none"]
}
}
},
"PropertyDefinitionUpdateInputSchema": {
"type": "object",
"properties": {
"description": {
"description": "Description explaining what the property represents",
"type": "string"
},
"tags": {
"description": "Tags to organize properties by product area (e.g. \"checkout\", \"onboarding\") or user journey stage (e.g. \"acquisition\", \"activation\", \"monetization\", \"retention\"). Warning: this REPLACES the property's entire tag list, it does not merge. To keep existing tags, include them alongside the new ones; to remove a tag, omit it. Omit this field entirely to leave tags unchanged.",
"type": "array",
"items": {
"type": "string"
}
},
"property_type": {
"description": "The data type of the property. Controls how the property is parsed, displayed, and filtered.",
"type": "string",
"enum": ["DateTime", "String", "Numeric", "Boolean", "Duration"]
},
"verified": {
"description": "Mark as verified to indicate the property is correctly instrumented and safe to use",
"type": "boolean"
},
"hidden": {
"description": "Mark property as no longer used. Hides it from the UI while preserving historical data",
"type": "boolean"
}
}
},
"PropertyDefinitionUpdateSchema": {
"type": "object",
"properties": {
"propertyName": {
"type": "string",
"description": "The exact name of the property to update (e.g. \"$browser\", \"plan_type\")"
},
"type": {
"default": "event",
"description": "Which property taxonomy the property belongs to. Defaults to \"event\" (event properties).",
"type": "string",
"enum": ["event", "person", "group", "session"]
},
"groupTypeIndex": {
"description": "Required when type is \"group\": the zero-based index of the group type the property belongs to.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"data": {
"type": "object",
"properties": {
"description": {
"description": "Description explaining what the property represents",
"type": "string"
},
"tags": {
"description": "Tags to organize properties by product area (e.g. \"checkout\", \"onboarding\") or user journey stage (e.g. \"acquisition\", \"activation\", \"monetization\", \"retention\"). Warning: this REPLACES the property's entire tag list, it does not merge. To keep existing tags, include them alongside the new ones; to remove a tag, omit it. Omit this field entirely to leave tags unchanged.",
"type": "array",
"items": {
"type": "string"
}
},
"property_type": {
"description": "The data type of the property. Controls how the property is parsed, displayed, and filtered.",
"type": "string",
"enum": ["DateTime", "String", "Numeric", "Boolean", "Duration"]
},
"verified": {
"description": "Mark as verified to indicate the property is correctly instrumented and safe to use",
"type": "boolean"
},
"hidden": {
"description": "Mark property as no longer used. Hides it from the UI while preserving historical data",
"type": "boolean"
}
},
"description": "The property definition data to update"
}
},
"required": ["propertyName", "data"]
},
"ReadDataSchemaSchema": {
"type": "object",
"properties": {
"query": {
"oneOf": [
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "events"
},
"limit": {
"description": "Number of events to return per page.",
"default": 500,
"type": "integer",
"minimum": 1,
"maximum": 500
},
"offset": {
"description": "Number of events to skip for pagination.",
"default": 0,
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": ["kind"]
},
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "event_properties"
},
"event_name": {
"type": "string",
"description": "The name of the event that you want to retrieve properties for."
}
},
"required": ["kind", "event_name"]
},
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "entity_properties"
},
"entity": {
"type": "string",
"description": "The type of the entity that you want to retrieve properties for."
}
},
"required": ["kind", "entity"]
},
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "action_properties"
},
"action_id": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "The ID of the action that you want to retrieve properties for."
}
},
"required": ["kind", "action_id"]
},
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "entity_property_values"
},
"entity": {
"type": "string",
"description": "The type of the entity that you want to retrieve properties for."
},
"property_name": {
"type": "string",
"description": "Verified property name of an entity."
}
},
"required": ["kind", "entity", "property_name"]
},
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "event_property_values"
},
"event_name": {
"type": "string",
"description": "Verified event name"
},
"property_name": {
"type": "string",
"description": "Verified property name of an event."
}
},
"required": ["kind", "event_name", "property_name"]
},
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "action_property_values"
},
"action_id": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Verified action ID"
},
"property_name": {
"type": "string",
"description": "Verified property name of an action."
}
},
"required": ["kind", "action_id", "property_name"]
}
],
"description": "The data schema query to execute."
}
},
"required": ["query"]
},
"SavedMetricsAttachSchema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "ID of an existing shared/saved metric. Discover IDs with experiment-saved-metrics-list."
},
"metadata": {
"description": "Optional per-link metadata. Omit to default this metric to primary.",
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["primary", "secondary"],
"description": "Whether this metric is a primary or secondary metric on the experiment."
}
},
"required": ["type"]
}
},
"required": ["id"]
},
"description": "The complete desired set of shared (saved) metrics for the experiment — this REPLACES all existing saved-metric links, it does not append. To add or remove one, first read the experiment's current saved_metrics via experiment-get and resend the full set. Pass an empty array to detach all shared metrics."
},
"ScoreDefinitionConfigSchema": {
"anyOf": [
{
"type": "object",
"properties": {
"options": {
"minItems": 1,
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string",
"minLength": 1,
"maxLength": 128,
"description": "Stable option key — lowercase letters, numbers, underscores, hyphens. Sent back when this option is selected."
},
"label": {
"type": "string",
"minLength": 1,
"maxLength": 256,
"description": "Human-readable label shown in the review UI."
}
},
"required": ["key", "label"]
},
"description": "Ordered categorical options. Must contain at least one option with unique keys."
},
"selection_mode": {
"description": "Whether reviewers select one option or many. Defaults to \"single\".",
"type": "string",
"enum": ["single", "multiple"]
},
"min_selections": {
"description": "Minimum selections required. Only valid when selection_mode is \"multiple\".",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"max_selections": {
"description": "Maximum selections allowed. Only valid when selection_mode is \"multiple\".",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
}
},
"required": ["options"],
"additionalProperties": false,
"description": "Config shape used when kind is \"categorical\"."
},
{
"type": "object",
"properties": {
"min": {
"description": "Optional inclusive minimum score.",
"type": "number"
},
"max": {
"description": "Optional inclusive maximum score (must be ≥ min).",
"type": "number"
},
"step": {
"description": "Optional increment step for numeric input, e.g. 1 or 0.5.",
"type": "number",
"exclusiveMinimum": 0
}
},
"additionalProperties": false,
"description": "Config shape used when kind is \"numeric\"."
},
{
"type": "object",
"properties": {
"true_label": {
"description": "Optional label shown for the true branch (e.g. \"Yes\").",
"type": "string",
"minLength": 1
},
"false_label": {
"description": "Optional label shown for the false branch (e.g. \"No\").",
"type": "string",
"minLength": 1
}
},
"additionalProperties": false,
"description": "Config shape used when kind is \"boolean\"."
}
],
"description": "Immutable scorer configuration. Pick the shape matching the scorer kind: categorical (options + selection_mode), numeric (min/max/step), or boolean (true_label/false_label). The server validates the shape against the kind on the parent scorer and returns 400 on a mismatch."
},
"UsageMetricFiltersSchema": {
"anyOf": [
{
"type": "object",
"properties": {
"source": {
"type": "string",
"const": "data_warehouse"
},
"table_name": {
"type": "string",
"description": "Name of a synced data warehouse table. Use `external-data-schemas-list` to discover available tables."
},
"timestamp_field": {
"type": "string",
"description": "Timestamp column or InsightsQL expression on the row (e.g. \"created\" or \"toDateTime(created_at)\"). Use `execute-sql` (`SELECT * FROM <table> LIMIT 1`) to inspect available columns."
},
"key_field": {
"type": "string",
"description": "Column on the row whose value matches the entity key. v1 supports group profiles only — the column value is compared to the group_key."
}
},
"required": ["source", "table_name", "timestamp_field", "key_field"],
"description": "Data-warehouse-source filter shape."
},
{
"type": "object",
"properties": {
"events": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Event name (e.g. \"$pageview\")."
},
"name": {
"type": "string"
},
"type": {
"type": "string",
"const": "events"
},
"order": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"properties": {
"type": "array",
"items": {}
}
},
"required": ["id"]
},
"description": "Events to count or sum over."
},
"actions": {
"type": "array",
"items": {}
},
"properties": {
"type": "array",
"items": {}
},
"filter_test_accounts": {
"type": "boolean"
}
},
"required": ["events"],
"description": "Events-source filter shape (default)."
}
],
"description": "Filter definition. Pick exactly one branch: `data_warehouse` (set `source: \"data_warehouse\"` plus `table_name`/`timestamp_field`/`key_field`) or `events` (InsightsFunction filter shape with an `events` array)."
},
"WorkflowActionEmailPatchSchema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The workflow (InsightsFlow) id."
},
"action_id": {
"type": "string",
"description": "Id of the function_email step whose email to edit."
},
"operations": {
"description": "Ordered edits applied atomically to the step's email design - the same operations as workflows-patch-email-template. The result is re-rendered to HTML server-side, so the sent email always matches the patched design. Reference blocks by id (read them via workflows-get).",
"minItems": 1,
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "update_content"
},
"id": {
"type": "string",
"description": "Id of the content block to update."
},
"patch": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Partial content-block fields, deep-merged into the existing block; a null leaf deletes that key. e.g. {values: {text: '<p>Hi</p>'}} changes only the block's text."
}
},
"required": ["op", "id", "patch"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "update_column"
},
"id": {
"type": "string",
"description": "Id of the column to update."
},
"patch": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Partial column fields, deep-merged; a null leaf deletes that key."
}
},
"required": ["op", "id", "patch"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "update_row"
},
"id": {
"type": "string",
"description": "Id of the row to update."
},
"patch": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Partial row fields, deep-merged; a null leaf deletes that key."
}
},
"required": ["op", "id", "patch"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "update_body"
},
"patch": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Partial body fields, deep-merged. e.g. {values: {backgroundColor: '#ffffff'}}."
}
},
"required": ["op", "patch"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "add_content"
},
"column_id": {
"type": "string",
"description": "Id of the column to insert the block into."
},
"content": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "A content block {type, values: {...}}; omit id and values._meta — they are assigned server-side. type is one of text, heading, button, image, divider, html, etc."
},
"index": {
"description": "0-based insert position; omit to append to the end.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": ["op", "column_id", "content"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "remove_content"
},
"id": {
"type": "string",
"description": "Id of the content block to remove."
}
},
"required": ["op", "id"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "move_content"
},
"id": {
"type": "string",
"description": "Id of the content block to move."
},
"column_id": {
"type": "string",
"description": "Id of the destination column."
},
"index": {
"description": "0-based position in the destination column; omit to append.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": ["op", "id", "column_id"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "add_row"
},
"row": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "A full row {cells, columns: [{contents: [...], values}], values}; ids and Unlayer numbering are assigned server-side for the row and everything nested in it."
},
"index": {
"description": "0-based insert position; omit to append to the end.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": ["op", "row"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "remove_row"
},
"id": {
"type": "string",
"description": "Id of the row to remove."
}
},
"required": ["op", "id"]
}
]
}
},
"email_patch": {
"description": "Partial email fields deep-merged into the step's email (a null leaf deletes the key): subject, preheader, text, to, from, replyTo, cc, bcc. The design is edited via operations, and html is always re-rendered from it.",
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"base_updated_at": {
"description": "Optimistic concurrency: the updated_at (or draft_updated_at) last loaded. If the stored workflow is newer, the patch is rejected with 409 instead of clobbering a concurrent edit.",
"type": "string"
}
},
"required": ["id", "action_id"]
},
"WorkflowGraphPatchSchema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The workflow (InsightsFlow) id to edit."
},
"operations": {
"minItems": 1,
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "update_action"
},
"id": {
"type": "string",
"description": "Id of the action to update."
},
"patch": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "Partial action fields, deep-merged into the existing action; a null leaf deletes that key. e.g. {config: {inputs: {subject: {value: \"Hi\"}}}} changes only that one input."
}
},
"required": ["op", "id", "patch"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "add_action"
},
"action": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {},
"description": "A full action node {id, name, type, config, ...}; same shape as entries in the workflow actions array."
}
},
"required": ["op", "action"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "remove_action"
},
"id": {
"type": "string",
"description": "Id of the action to remove. Its incoming edges reconnect to its first outgoer."
}
},
"required": ["op", "id"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "add_edge"
},
"edge": {
"type": "object",
"properties": {
"from": {
"type": "string",
"description": "Source action id."
},
"to": {
"type": "string",
"description": "Target action id."
},
"type": {
"type": "string",
"enum": ["continue", "branch"],
"description": "'continue' = fall-through (sequential or no-match path); 'branch' = a condition/cohort branch (needs index)."
},
"index": {
"description": "Required for type=branch: which condition/cohort slot this branch matches (0-based).",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": ["from", "to", "type"],
"description": "The edge to add."
}
},
"required": ["op", "edge"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "remove_edge"
},
"edge": {
"type": "object",
"properties": {
"from": {
"type": "string",
"description": "Source action id."
},
"to": {
"type": "string",
"description": "Target action id."
},
"type": {
"type": "string",
"enum": ["continue", "branch"],
"description": "'continue' = fall-through (sequential or no-match path); 'branch' = a condition/cohort branch (needs index)."
},
"index": {
"description": "Required for type=branch: which condition/cohort slot this branch matches (0-based).",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": ["from", "to", "type"],
"description": "The edge to remove (matched on from/to/type/index)."
}
},
"required": ["op", "edge"]
},
{
"type": "object",
"properties": {
"op": {
"type": "string",
"const": "replace_action_edges"
},
"id": {
"type": "string",
"description": "Action id whose outgoing edges are being replaced."
},
"edges": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from": {
"type": "string",
"description": "Source action id."
},
"to": {
"type": "string",
"description": "Target action id."
},
"type": {
"type": "string",
"enum": ["continue", "branch"],
"description": "'continue' = fall-through (sequential or no-match path); 'branch' = a condition/cohort branch (needs index)."
},
"index": {
"description": "Required for type=branch: which condition/cohort slot this branch matches (0-based).",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": ["from", "to", "type"]
},
"description": "The complete set of the action's outgoing edges; incoming edges are preserved."
}
},
"required": ["op", "id", "edges"]
}
]
},
"description": "Ordered graph edits applied atomically: the stored graph is read, ops are applied in order, the result is fully validated, and it is saved only if valid — otherwise the workflow is left unchanged. Reference nodes/edges by id so you never resend the whole graph. The full updated workflow is returned."
}
},
"required": ["id", "operations"]
}
}
}