{"name":"KontrolX","description":"KontrolX governed Profile-attribution agent — Profiles, Intakes, Enrichments, Placements, Lifecycles, Actions, Capsules, Datasets, and Webhooks.","url":"https://s-mcp-core.kx21.com/a2a","version":"docker","capabilities":{"streaming":false,"pushNotifications":false,"stateTransitionHistory":false},"defaultInputModes":["application/json"],"defaultOutputModes":["application/json"],"securitySchemes":{"jwtBearer":{"type":"http","scheme":"bearer"}},"security":[{"jwtBearer":[]}],"skills":[{"id":"kx_toolkit","name":"kx_toolkit","description":"What this connection can do beyond the tools listed here. The listed set is what a session reaches for constantly — reads, search, catalogs, placements, intakes, lifecycle, actions. Everything else (configuring a Workflow, its screeners, enrichments and buyers; creating vendors, buyers, dashboards, datasets, knowledge bases, webhook subscriptions; bulk loads; sample activity) is REAL and available, just not listed, because their schemas would cost this conversation ~25,000 tokens before you asked a question. Call with no query to see every one by name, or with a query ('configure buyer routing', 'bulk load profiles') to get full schemas. Then invoke with kx_call. If a task seems impossible with the listed tools, call this BEFORE telling anyone it cannot be done — it almost certainly can.","tags":["kx"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"query":{"description":"Plain words describing what you want to do. Every word must appear in the tool name or description, so fewer words match more. Omit to list every available tool by name.","type":"string"}},"additionalProperties":false}},{"id":"kx_call","name":"kx_call","description":"Invoke a tool that kx_toolkit named. Pass { tool: \"<name>\", args: { … } }. The arguments go through that tool's own schema, permissions, and environment rules unchanged — this is how it is reached, not a way around any of them. Get the exact argument shape from kx_toolkit first; guessing it produces a validation error, not a silent partial write.","tags":["kx"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"tool":{"type":"string","minLength":1,"description":"The tool name exactly as kx_toolkit reported it."},"args":{"description":"That tool's arguments, matching the schema kx_toolkit returned.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["tool"],"additionalProperties":false}},{"id":"catalog_list_profile_types","name":"catalog_list_profile_types","description":"List Profile Types available to the caller's org (global defaults + org-specific). A Profile Type is the durable identity model for governed entities and may be used without any Workflow. A real Workflow can also lock to one Profile Type. Returned ids are used by profile_create/profile_list and workflow_create. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["catalog"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"catalog_list_workflows","name":"catalog_list_workflows","description":"List Workflows defined in the caller's org. A Workflow is a real channel or production line for arriving business events, locked to one Profile Type; it owns Intake screening, fixed Enrichment/action plans, and lifecycle transitions. Profile-only inventory/history needs no Workflow. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["catalog"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"catalog_list_vendors","name":"catalog_list_vendors","description":"List Vendors in the caller's org. A Vendor is a real party that delivers events into a chosen Workflow, performs Enrichment/screening, or both. Cost traceability is available when a cost exists but is not what defines a Vendor. Partner keys and Enrichment results carry vendor attribution. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["catalog"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"catalog_list_buyers","name":"catalog_list_buyers","description":"List Buyers configured in the caller's org. A Buyer is a downstream destination for a potential or completed sale represented by a Placement. partner_buyer API keys are bound to a buyerId and can accept, reject, or return routed Placements. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["catalog"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"catalog_list_screener_types","name":"catalog_list_screener_types","description":"List screener types available to the caller's org. A screener decides whether a lead may proceed, before any enrichment cost is incurred. WHEN each one runs is a per-step setting on the workflow, not a property of the type: mode 'pre_ping' runs both when a supplier pings to ask whether we would take a lead AND on the posted lead, while mode 'post' only ever sees a posted lead. So a workflow whose screeners are all 'post' answers a ping having screened nothing — a lock surfaces as intake_preping's { locked: true, reason }, and that call can only report what the 'pre_ping' steps decided. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["catalog"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"catalog_list_enrichment_types","name":"catalog_list_enrichment_types","description":"List Enrichment Types available to the caller's org, including Profile-level bulk/on-demand integrations and types fixed into Workflow pipelines. An Enrichment wraps an external or internal lookup with attributed history and optional cost/accounting metadata. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["catalog"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"catalog_list_action_types","name":"catalog_list_action_types","description":"List action types defined in the caller's org. An action type names a fireable side-effect (welcome email, SMS verify, CRM push, etc.). The returned id is the actionTypeId argument to action_fire. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["catalog"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"catalog_get_workflow_enrichment_steps","name":"catalog_get_workflow_enrichment_steps","description":"Return a workflow's current enrichment pipeline steps with each step's full integration config and its `wave` — which steps run at the same time, and what waits for what. Call this BEFORE workflow_enrichment_pipeline_configure to APPEND a step: that tool replaces ALL steps, so send the existing ones back WITH their wave numbers plus the new one, or the rewrite collapses a staged pipeline into one wave that fires everything at once. A step reported as wave 0 can never run — it waits on a cycle or on something no longer in the pipeline.","tags":["catalog"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the workflow whose enrichment pipeline steps to retrieve."}},"required":["workflowId"],"additionalProperties":false}},{"id":"catalog_get_workflow_screener_steps","name":"catalog_get_workflow_screener_steps","description":"Return a workflow's current screener pipeline: each step's workflowScreenerId, code, name, `wave`, `waveRule`, mode, enabled flag, and stored config. Call this BEFORE workflow_screener_pipeline_configure — that tool REPLACES the whole pipeline, so a call made without reading first drops the steps you did not mention, their operator-set config, and the waves that say what runs together. `wave` is 1-based and steps sharing one run at the same time; `waveRule` is what that wave takes — 'all' (every member must pass) or 'any' (one passing member carries it). mode 'pre_ping' answers a supplier's ping AND the posted lead; 'post' only ever sees a posted lead. hasIntegration false on a custom screener means it has nowhere to send its request, so it cannot answer and refuses every lead.","tags":["catalog"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the workflow whose screener pipeline to retrieve."}},"required":["workflowId"],"additionalProperties":false}},{"id":"action_list","name":"action_list","description":"List the most recent fired actions in the caller's org (org-wide scope). For per-profile scope use profile_get_actions. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["action"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"action_get","name":"action_get","description":"Get a single fired-action record by id. Returns the full row.","tags":["action"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"actionId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the action record. From action_list[*].id."}},"required":["actionId"],"additionalProperties":false}},{"id":"action_fire","name":"action_fire","description":"Fire an action on a profile. Returns a RECEIPT { id, status } — not the full record. Use action_get with the returned id to retrieve the full row once status reaches \"received\".","tags":["action"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile the action targets. From profile_list[*].id."},"actionTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the action type to fire. From catalog_list_action_types[*].id."},"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Optional free-form request payload merged into the action record. Shape depends on action type — check the action type definition."}},"required":["profileId","actionTypeId"],"additionalProperties":false}},{"id":"profile_list","name":"profile_list","description":"List profiles visible to the caller's role. Supports profileTypeId filter, limit, and createdAt cursor (before, ISO 8601). Use profile_get_lifecycles for per-profile history.","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Optional UUID filter — return only profiles of this profile type. From catalog_list_profile_types[*].id or catalog_list_workflows[*].profileTypeId."},"limit":{"type":"integer","exclusiveMinimum":0,"maximum":500,"description":"Max rows to return (1–500, default 50)."},"before":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$","description":"ISO 8601 datetime cursor — return profiles created strictly before this time."}},"additionalProperties":false}},{"id":"profile_get","name":"profile_get","description":"Get one profile by id. Returns the bare row. Use profile_get_intakes / _enrichments / _actions / _lifecycles for related sub-resources.","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile. From profile_list[*].id."}},"required":["profileId"],"additionalProperties":false}},{"id":"profile_create","name":"profile_create","description":"Create a profile under the caller's org. customer_admin only. Returns the created row (bare).","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile type. Discoverable from catalog_list_profile_types[*].id, or read directly off catalog_list_workflows[*].profileTypeId (each workflow declares the profile type it operates on)."},"attributes":{"default":{},"type":"object","properties":{"email":{"type":"string","description":"Primary email address for the profile."},"phone":{"type":"string","description":"Primary phone number (E.164 or local)."},"firstName":{"type":"string","description":"Given name."},"lastName":{"type":"string","description":"Family name."},"profileTypeId":{"type":"string","description":"UUID of the profile type from catalog_list_profile_types."}},"additionalProperties":false,"description":"Initial attributes — email/phone/firstName/lastName all optional."}},"required":["profileTypeId","attributes"],"additionalProperties":false}},{"id":"profile_bulk_load","name":"profile_bulk_load","description":"Bulk-load HISTORIC Profile facts from CSV text at any time with NO pipeline (no screeners, Enrichment cost, Placements, or lifecycle). Dedupes + merges on identifiers via upsert. Caps at 500 rows/call; continue with nextOffset when returned. THE LOADER RETAINS ONLY THESE HEADERS (snake_case or camelCase): email, phone, first_name, last_name, address_line1, address_line2, city, region/state, postal_code/zip, country, and ONE identifier_type/identifier_value pair. The allowlist is fixed and global — a custom Profile Type does not extend it. Audit every supplied header against that list BEFORE calling. Every supplied header is preserve-or-stop: if ANY is unsupported, stop the whole file — no partial load, no supported subset, no splitting a field elsewhere, no Dataset or fake Workflow substitute, and never ask for a reduced or reshaped file. Rows process independently, so partial success is possible: inspect `failed` and every `results` entry, report each error, preserve the input, and never declare completion while rows failed.","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"csv":{"type":"string","minLength":1,"maxLength":5000000,"description":"CSV text: a header row followed by one profile per data row (~5MB max)."},"profileTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Optional profile type UUID (from catalog_list_profile_types[*].id). Defaults to Person."},"offset":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Zero-based data-row offset to resume from. Pass a prior call’s nextOffset."}},"required":["csv"],"additionalProperties":false}},{"id":"profile_update","name":"profile_update","description":"Patch a profile's attributes. customer_admin only. Only provided attribute fields are updated; others are left unchanged. Returns the updated row (bare).","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile to update. From profile_list[*].id."},"attributes":{"default":{},"type":"object","properties":{"email":{"type":"string","description":"Primary email address for the profile."},"phone":{"type":"string","description":"Primary phone number (E.164 or local)."},"firstName":{"type":"string","description":"Given name."},"lastName":{"type":"string","description":"Family name."},"profileTypeId":{"type":"string","description":"UUID of the profile type from catalog_list_profile_types."}},"additionalProperties":false,"description":"Fields to patch. Omitted fields keep their existing values."}},"required":["profileId","attributes"],"additionalProperties":false}},{"id":"profile_get_intakes","name":"profile_get_intakes","description":"List intakes attached to a profile (every intake that flowed into this profile via dedupe). Returns a bare array.","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile. From profile_list[*].id."}},"required":["profileId"],"additionalProperties":false}},{"id":"profile_get_enrichments","name":"profile_get_enrichments","description":"List enrichments performed on a profile. Returns a bare array (empty if none).","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile. From profile_list[*].id."}},"required":["profileId"],"additionalProperties":false}},{"id":"profile_get_actions","name":"profile_get_actions","description":"List action runs on a profile (per-profile scope). Returns a bare array. Compare action_list for org-wide scope.","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile. From profile_list[*].id."}},"required":["profileId"],"additionalProperties":false}},{"id":"profile_get_lifecycles","name":"profile_get_lifecycles","description":"List ALL lifecycle rows for a profile, including closed. Returns a bare array. Use this for history; use lifecycle_get for the single OPEN lifecycle (errors if none).","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile. From profile_list[*].id."}},"required":["profileId"],"additionalProperties":false}},{"id":"profile_count","name":"profile_count","description":"Return the total number of profiles visible to the caller's role, with optional period filtering and groupBy aggregation. partner_source and partner_buyer keys are narrowed by their visibility bindings; customer roles see org-wide counts. Use period (today/yesterday/last_7d/last_30d/all) for common date windows, or since/until for custom ISO 8601 bounds. groupBy=profileType returns a bucket array alongside the total.","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"period":{"description":"Server-resolved date window (UTC). Overrides since/until. Default all.","type":"string","enum":["today","yesterday","last_7d","last_30d","all"]},"since":{"description":"ISO 8601 lower bound (inclusive). Ignored if period set.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"until":{"description":"ISO 8601 upper bound (exclusive). Ignored if period set.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"profileTypeId":{"description":"Filter by profile type UUID.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"groupBy":{"description":"Group counts by a dimension; omit for a single total.","type":"string","enum":["profileType"]}},"additionalProperties":false}},{"id":"webhook_list","name":"webhook_list","description":"List webhooks registered for the caller's org. Returns a bare array. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["webhook"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"webhook_get","name":"webhook_get","description":"Get one webhook by id. signingSecret is NEVER returned by reads — only on create.","tags":["webhook"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"webhookId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the webhook subscription. From webhook_list[*].id."}},"required":["webhookId"],"additionalProperties":false}},{"id":"webhook_create","name":"webhook_create","description":"Create a webhook subscription for the caller's org. customer_admin only. Returns signingSecret ONCE — save it immediately; the secret cannot be retrieved later (revoke + re-create if lost).","tags":["webhook"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Human-readable name for this subscription (audit + admin UI display)."},"url":{"type":"string","format":"uri","description":"HTTPS endpoint that will receive POST deliveries for matching events."},"events":{"minItems":1,"type":"array","items":{"type":"string","enum":["intake.created","lifecycle.created","lifecycle.transitioned","lifecycle.closed","enrichment.received","action.fired","placement.routed","placement.accepted","placement.rejected","placement.returned","webhook.delivered"]},"description":"One or more event types to subscribe to. Canonical types: intake.created, lifecycle.created, lifecycle.transitioned, lifecycle.closed, enrichment.received, action.fired, placement.routed, placement.accepted, placement.rejected, placement.returned, webhook.delivered. Typed events like \"enrichment.received:phone_verify\" or \"action.fired:welcome_email\" are also accepted as raw strings."}},"required":["name","url","events"],"additionalProperties":false}},{"id":"webhook_update","name":"webhook_update","description":"Patch a webhook subscription. Only provided fields are updated. customer_admin only.","tags":["webhook"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"webhookId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the webhook to update. From webhook_list[*].id."},"name":{"type":"string","minLength":1,"description":"New display name."},"url":{"type":"string","format":"uri","description":"New target HTTPS endpoint."},"events":{"minItems":1,"type":"array","items":{"type":"string","enum":["intake.created","lifecycle.created","lifecycle.transitioned","lifecycle.closed","enrichment.received","action.fired","placement.routed","placement.accepted","placement.rejected","placement.returned","webhook.delivered"]},"description":"Full replacement event list. See webhook_create for valid event strings."},"isActive":{"type":"boolean","description":"Pause (false) or resume (true) deliveries."}},"required":["webhookId"],"additionalProperties":false}},{"id":"webhook_delete","name":"webhook_delete","description":"Hard-delete a webhook subscription. Future events of subscribed types stop firing. customer_admin only. Returns { ok: true }.","tags":["webhook"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"webhookId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the webhook to delete. From webhook_list[*].id."}},"required":["webhookId"],"additionalProperties":false}},{"id":"webhook_get_deliveries","name":"webhook_get_deliveries","description":"List recent delivery attempts for a webhook. Returns a bare array (oldest empty for fresh subscriptions).","tags":["webhook"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"webhookId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the webhook. From webhook_list[*].id."}},"required":["webhookId"],"additionalProperties":false}},{"id":"webhook_replay_delivery","name":"webhook_replay_delivery","description":"Re-enqueue a failed (or successful) delivery. Throws GoneError (410) if the source event has been pruned. customer_admin only.","tags":["webhook"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"webhookId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the webhook. From webhook_list[*].id."},"deliveryId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the specific delivery attempt to replay. From webhook_get_deliveries."}},"required":["webhookId","deliveryId"],"additionalProperties":false}},{"id":"lifecycle_get","name":"lifecycle_get","description":"Get the OPEN lifecycle row for a profile. Throws \"no open lifecycle for profile X\" if the profile has no open lifecycle (closed or never started). For full history including closed lifecycles, use profile_get_lifecycles instead.","tags":["lifecycle"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile whose open lifecycle you want. From profile_list[*].id."}},"required":["profileId"],"additionalProperties":false}},{"id":"lifecycle_list","name":"lifecycle_list","description":"List lifecycle rows in the caller's org. Optional state filter narrows the result. Workflow-specific states may also be valid beyond the enum hint.","tags":["lifecycle"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"state":{"type":"string","minLength":1,"description":"Lifecycle state code. Default machine: intake, discovery, motion, trial, closed. State machines are per-Workflow — read the real codes with workflow_lifecycle_get."},"limit":{"type":"integer","exclusiveMinimum":0,"maximum":500,"description":"Max rows to return (1–500, default 50)."}},"additionalProperties":false}},{"id":"lifecycle_transition","name":"lifecycle_transition","description":"Transition a profile's open lifecycle to a new state code. Throws ConflictError if the transition is invalid for the workflow, or if expectedVersion doesn't match (optimistic concurrency).","tags":["lifecycle"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the profile whose lifecycle to transition. From profile_list[*].id."},"toStateCode":{"type":"string","minLength":1,"description":"Target state code. Default machine: intake, discovery, motion, trial, closed, but state machines are per-Workflow — read legal codes/edges with workflow_lifecycle_get (define custom ones with workflow_lifecycle_configure). Only edges with manualAllowed: true accept manual transitions; unknown codes or illegal transitions return ConflictError."},"expectedVersion":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Current lifecycle version (optimistic lock). Get this from lifecycle_get.version. If it does not match, ConflictError is returned. Default 0 lets the server skip the check — risky under concurrent writes."},"reason":{"type":"string","description":"Optional human-readable reason for the transition (audit log)."}},"required":["profileId","toStateCode","expectedVersion"],"additionalProperties":false}},{"id":"placement_list","name":"placement_list","description":"List placements visible to the caller. Partner keys bound to a buyer see only buyer-scoped placements; customer roles see org-wide placements (with profile-visibility narrowing applied). Each row carries workflowCode + vendorId + vendorCode (inherited from the originating intake) so vendor-level rollups (e.g., \"which vendor produced the most placements\") can be computed in a single pass without joining catalog_list_workflows or catalog_list_vendors.","tags":["placement"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"status":{"type":"string","enum":["pending","accepted","rejected","returned","routing_unrouted"],"description":"Optional status filter. pending = routed but not yet accepted; accepted = buyer accepted; rejected = buyer rejected; returned = buyer returned after accept; routing_unrouted = no eligible buyer found."},"before":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$","description":"ISO 8601 datetime cursor — return rows created strictly before this time."},"limit":{"type":"integer","exclusiveMinimum":0,"maximum":200,"description":"Max rows to return (1–200, default 50)."}},"additionalProperties":false}},{"id":"placement_get","name":"placement_get","description":"Get a placement by id. Returns the bare row (no envelope). Partner keys may only fetch placements routed to their bound buyer; cross-buyer reads return NotFoundError (existence-hiding).","tags":["placement"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"placementId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the placement. From placement_list[*].id."}},"required":["placementId"],"additionalProperties":false}},{"id":"placement_accept","name":"placement_accept","description":"Accept a placement as the bound buyer. Requires a partner_buyer key with buyerId binding — customer keys cannot accept. Idempotent on already-accepted rows.","tags":["placement"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"placementId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the placement to accept. From placement_list[*].id where status=\"pending\"."},"buyerReference":{"type":"string","description":"Optional buyer-side reference (CRM id, order id, etc.) recorded on the row."}},"required":["placementId"],"additionalProperties":false}},{"id":"placement_reject","name":"placement_reject","description":"Reject a placement as the bound buyer. Requires a partner_buyer key with buyerId binding. Terminal — the placement will not re-route to the same buyer.","tags":["placement"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"placementId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the placement to reject. From placement_list[*].id where status=\"pending\"."},"kind":{"type":"string","enum":["not_interested","missing_information"],"description":"Reject reason category. not_interested = buyer declines on merit; missing_information = profile lacks data the buyer needs to evaluate."},"reason":{"type":"string","description":"Free-form human-readable reason (audit log + analytics)."}},"required":["placementId"],"additionalProperties":false}},{"id":"placement_return","name":"placement_return","description":"Return a previously accepted placement (post-accept refund/clawback). Requires a partner_buyer key with buyerId binding. Only valid on placements currently in status=\"accepted\".","tags":["placement"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"placementId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"UUID of the accepted placement to return. From placement_list[*].id where status=\"accepted\"."},"reason":{"type":"string","minLength":1,"description":"Required human-readable return reason (audit log + dispute resolution)."}},"required":["placementId","reason"],"additionalProperties":false}},{"id":"placement_count","name":"placement_count","description":"Return the total number of placements visible to the caller, with optional period filtering and groupBy aggregation. partner_buyer keys are scoped to their bound buyer; customer roles see org-wide counts. Use period (today/yesterday/last_7d/last_30d/all) for common date windows, or since/until for custom ISO 8601 bounds. groupBy=status or groupBy=buyer returns a bucket array alongside the total.","tags":["placement"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"period":{"description":"Server-resolved date window (UTC). Overrides since/until. Default all.","type":"string","enum":["today","yesterday","last_7d","last_30d","all"]},"since":{"description":"ISO 8601 lower bound (inclusive). Ignored if period set.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"until":{"description":"ISO 8601 upper bound (exclusive). Ignored if period set.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"status":{"description":"Filter by placement status.","type":"string","enum":["pending","accepted","rejected","returned","routing_unrouted"]},"groupBy":{"description":"Group counts by dimension; omit for a single total.","type":"string","enum":["status","buyer"]}},"additionalProperties":false}},{"id":"intake_create","name":"intake_create","description":"Submit a real arriving business event. Returns a RECEIPT { intakeId, status, dedupe } for a real event through a real Workflow, then runs the full pipeline asynchronously. Never use this tool to manufacture an intakeId for inventory or Profile-only history. Use profile_get_intakes or webhook events to observe progress.\n\nAUTH: Requires a partner_source API key (not a customer_admin key). To get one:\n  1. Call catalog_list_workflows to discover available workflow IDs.\n  2. In the admin UI go to Workflows → open the workflow → Vendors tab → expand the vendor → \"Issue key\". The key is bound to that workflow + vendor. (/admin/api-keys only mints customer_admin / customer_user keys.)\n  3. Configure the MCP server to use that bearer token instead of the customer_admin key.\nIf you hit a missing-scope error, the current key lacks the workflow_id + vendor_id binding — follow the steps above.","tags":["intake"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Free-form intake payload. Shape depends on the workflow — typically includes contact attributes (email, phone, firstName, lastName) plus workflow-specific fields. Validated against the workflow schema if one is configured."}},"required":["payload"],"additionalProperties":false}},{"id":"intake_preping","name":"intake_preping","description":"Run pre-ping screening checks against an intake-shaped payload WITHOUT creating an intake. Returns { locked: false } when the payload is clear, or { locked: true, reason } naming the single check that locked it out (blacklist, duplicate_sold, duplicate_window, reentry_denied_rejected, reentry_denied_disqualified, reentry_denied_awaiting, reentry_denied_stuck, buyer_screeners_rejected). There is no `reasons` array and no `accepted` field on either of those — `accepted: false` with a `code` appears ONLY when the pre-ping could not run at all (missing_identifier, workflow_not_found, workflow_inactive). Use this to validate a real arriving event before committing it.\n\nAUTH: Same partner_source key requirement as intake_create — needs vendor_id + workflow_id binding. Call catalog_list_workflows to find the intended Workflow, then in the admin UI open that Workflow → Vendors → expand the bound Vendor → Issue key. Point the MCP server at that partner_source bearer. /admin/api-keys only creates customer_admin or customer_user keys.","tags":["intake"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Same shape as intake_create.payload — the candidate intake to evaluate against pre-ping screeners."}},"required":["payload"],"additionalProperties":false}},{"id":"intake_count","name":"intake_count","description":"Return the total number of intakes visible to the caller, with optional period filtering and groupBy aggregation. partner_source keys are scoped to their bound workflow; customer roles see org-wide counts. Use period (today/yesterday/last_7d/last_30d/all) for common date windows, or since/until for custom ISO 8601 bounds. groupBy=status returns a bucket array alongside the total.","tags":["intake"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"period":{"description":"Server-resolved date window (UTC). Overrides since/until. Default all.","type":"string","enum":["today","yesterday","last_7d","last_30d","all"]},"since":{"description":"ISO 8601 lower bound (inclusive). Ignored if period set.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"until":{"description":"ISO 8601 upper bound (exclusive). Ignored if period set.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"status":{"description":"Filter by intake status.","type":"string","enum":["received","qualified","rejected","placed","returned","disqualified"]},"workflowId":{"description":"Filter by workflow UUID.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"groupBy":{"description":"Group counts by dimension; omit for single total.","type":"string","enum":["status","workflow"]}},"additionalProperties":false}},{"id":"intake_bulk_load","name":"intake_bulk_load","description":"Submit a CSV of real arriving events through the FULL intake pipeline — every row runs ingestIntake (screeners, dedupe, routing) attributed to the given vendor + workflow. Use for bulk files (e.g. an emailed vendor CSV) after mapping columns; use profile_bulk_load instead for historic Profile-only inventory with no pipeline. Row caps: 500 for inline csvText; 50,000 for stored-file r2Key loads (they run durably on the worker). csvText is the raw CSV including a header row; columnMapping optionally renames CSV headers to intake field names ({ \"EmailAddress\": \"email\" }). Accepts the raw csvText OR the r2Key of an already-stored file (inbound-email conversions expose convertedKey in the mission input). Returns { accepted, rejected, results[] } with per-row intakeIds and rejection reasons. AUTH: customer_admin keys work org-wide; partner_source keys may only load their own bound workflow.","tags":["intake"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"vendorId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"csvText":{"description":"Raw CSV content INCLUDING the header row. Never pass a storage key here.","type":"string","minLength":1,"maxLength":5000000},"r2Key":{"description":"Storage key of an already-uploaded CSV (an inbound-email file — pass the convertedKey from the mission input; it starts with \"inbound-email/\"). Provide exactly one of csvText | r2Key.","type":"string","minLength":1},"columnMapping":{"description":"Optional rename: { csvHeader: intakeFieldName }. Unmapped headers pass through.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["workflowId","vendorId"],"additionalProperties":false}},{"id":"enrichment_submit","name":"enrichment_submit","description":"Submit an Enrichment result back to KontrolX with a partner_enrichment API key bound to a Vendor, Enrichment Type, and when configured a Profile Type; bindings are server-derived and never passed in payload. This is a valid standalone Profile Enrichment result callback and result-ingestion callback only; it never invokes a provider or triggers Vendor execution. It is not the configure/trigger/poll operator batch path. For async Intake-bound work, pass the real intakeId. For unsolicited/standalone Profile Enrichment, pass intakeId:null and the identifiers configured by the key-bound Profile Type in payload so KontrolX can resolve/upsert the governed Profile. It accepts neither profile_id nor profileId and is never profileId-keyed; it is VIN-keyed only when VIN is configured on the key-bound Profile Type and supplied in payload. Never fabricate an Intake. The current MCP cannot configure, trigger, or poll customer-admin Profile Type bulk execution. Returns the Enrichment row.","tags":["enrichment"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Vendor-shaped enrichment result payload. Validated against the enrichmentType schema if one is configured. May include nested artifacts uploaded via enrichment_get_upload_url."},"intakeId":{"default":null,"description":"Optional correlation id linking the result back to the originating intake. Null when the enrichment is unsolicited / standalone.","type":["string","null"]},"costAmountCents":{"default":null,"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Optional vendor cost in cents (integer) — recorded for billing reconciliation."},"costCurrency":{"type":"string","description":"ISO 4217 currency code for costAmountCents (e.g., \"USD\"). Required if cost is set."}},"required":["payload","intakeId","costAmountCents"],"additionalProperties":false}},{"id":"enrichment_get_upload_url","name":"enrichment_get_upload_url","description":"Mint a pre-signed R2 PUT URL for uploading a binary enrichment artifact (PDF report, audio recording, etc.). Requires a partner_enrichment API key bound to a vendorId + enrichmentType. Returns { uploadUrl, objectKey } — PUT the binary to uploadUrl, then reference objectKey inside the payload submitted via enrichment_submit.","tags":["enrichment"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"contentType":{"type":"string","description":"MIME type of the file you intend to upload (e.g., \"application/pdf\"). Used to lock the pre-signed URL."},"filename":{"type":"string","description":"Original filename — used for the stored object key suffix only; never executed."}},"additionalProperties":false}},{"id":"enrichment_test","name":"enrichment_test","description":"Dry-run an enrichment integration against a sample Profile and its real existing Intake. This tool requires a real Intake: both profileId and intakeId are required. It resolves inputFields, makes the SSRF-guarded vendor call, and returns request + response without creating an Enrichment or charging configured cost. Never fabricate an Intake for Profile-only data. Profile-only bulk execution is an operator action in the Profile Type admin UI and remains a current MCP capability gap. Authorization is never echoed. WARNING: this makes a real outbound HTTP call, so user approval is required.","tags":["enrichment"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"integration":{"type":"object","properties":{"endpoint":{"type":"string","format":"uri"},"missionInstructions":{"type":"string","minLength":1},"profileLookup":{"type":"object","properties":{"match":{"type":"object","properties":{"fromPayloadPath":{"type":"string","minLength":1},"profileTypeCode":{"type":"string","minLength":1},"identifierType":{"type":"string","minLength":1}},"required":["fromPayloadPath","profileTypeCode","identifierType"],"additionalProperties":false},"pull":{"minItems":1,"type":"array","items":{"type":"string","minLength":1}},"maxAgeDays":{"type":"integer","exclusiveMinimum":0,"maximum":36500},"skipEnrichmentCodes":{"default":[],"type":"array","items":{"type":"string","minLength":1}}},"required":["match","pull","maxAgeDays","skipEnrichmentCodes"],"additionalProperties":false},"knowledge":{"type":"object","properties":{"kbId":{"type":"string","minLength":1},"questionFromPath":{"type":"string","minLength":1},"limit":{"default":6,"type":"integer","minimum":1,"maximum":20}},"required":["kbId","questionFromPath","limit"],"additionalProperties":false},"method":{"type":"string","enum":["GET","POST"]},"format":{"type":"string","enum":["json","form","raw"]},"bodyTemplate":{"type":"string","maxLength":16384},"contentType":{"type":"string","maxLength":256},"inputFields":{"default":[],"type":"array","items":{"anyOf":[{"type":"string","minLength":1},{"type":"object","properties":{"key":{"type":"string","minLength":1},"kind":{"type":"string","enum":["field","literal"]},"source":{"type":"string"},"transform":{"anyOf":[{"type":"string","enum":["trim","upper","lower","digits","phone10","nospace","yesno","date:YYYY-MM-DD","date:MM/DD/YYYY"]},{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"phone"},"style":{"type":"string","enum":["digits10","e164","pretty","digits"]}},"required":["kind","style"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"pattern":{"type":"string","minLength":1,"maxLength":32}},"required":["kind","pattern"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":200},"replaceWith":{"default":"","type":"string","maxLength":200},"regex":{"default":false,"type":"boolean"},"all":{"default":true,"type":"boolean"},"ignoreCase":{"default":false,"type":"boolean"}},"required":["kind","find","replaceWith","regex","all","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"extract"},"pattern":{"type":"string","minLength":1,"maxLength":200},"group":{"default":0,"type":"integer","minimum":0,"maximum":20}},"required":["kind","pattern","group"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"fallback":{"type":"string"},"ignoreCase":{"default":true,"type":"boolean"}},"required":["kind","values","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"template"},"pattern":{"type":"string","minLength":1,"maxLength":400}},"required":["kind","pattern"],"additionalProperties":false}]}]}},"required":["key","kind","source"],"additionalProperties":false}]}},"asyncMode":{"type":"boolean"},"timeoutMs":{"type":"integer","exclusiveMinimum":0,"maximum":60000},"failMode":{"type":"string","enum":["soft","hard"]},"attempts":{"type":"integer","minimum":1,"maximum":5},"authMode":{"type":"string","enum":["none","bearer","basic","raw"]},"authHeaderName":{"type":"string"},"authEnvVar":{"type":"string"},"headers":{"type":"object","propertyNames":{"type":"string","maxLength":128},"additionalProperties":{"type":"string","maxLength":2048}},"sendCallbackFields":{"type":"boolean"},"callbackFields":{"maxItems":3,"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["enrichment_id","callback_url","entry_url"]},"key":{"type":"string","minLength":1,"maxLength":128}},"required":["field","key"],"additionalProperties":false}}},"required":["inputFields"],"additionalProperties":false,"description":"The enrichment integration config to test. Matches the shape used in enrichment_type.integration."},"profileId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"A sample profile to resolve inputFields from (use profile_list to pick one)."},"intakeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"A sample intake for that profile (use profile_get_intakes to list intakes)."},"enrichmentTypeId":{"description":"Optional: if the enrichment_type already exists, pass its id to apply the stored encrypted credential. Omit when testing a draft config before the type is created.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["integration","profileId","intakeId"],"additionalProperties":false}},{"id":"profile_type_create","name":"profile_type_create","description":"Create or update the identity model for a durable governed Profile: code, name, identifiers, and kind. Upserts on (org_id, code). This tool does not create arbitrary Profile storage/attribute fields or columns and does not expand profile_bulk_load. A Profile Type can stand alone for entity inventory/history and does not require a Workflow. kind declares person | asset | organization | event; omitted → person on create, existing kind preserved on update. `event` is for durable records of moments (calls) that later Workflows connect to by exact identifier — never routed to Buyers. Create a Workflow afterward only when discovery identifies a real arriving business event or production line. identifiers is AUTHORITATIVE over every bound Workflow intake shape: workflow_create and workflow_update_rules reject a non-empty inputValidationRules that never requires one of these fields.","tags":["profile"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1},"identifiers":{"minItems":1,"type":"array","items":{"type":"string"}},"kind":{"type":"string","enum":["person","asset","organization","event"]}},"required":["code","name","identifiers"],"additionalProperties":false}},{"id":"workflow_create","name":"workflow_create","description":"Create or update a Workflow for a real business event, channel, or production line. A Workflow IS the line: it owns its required data, screening, Enrichment, routing and Buyers, with no configurable layer beneath it. It locks to exactly ONE Profile Type — the primary entity whose history the arriving event attributes to — and a secondary identifier in the payload cannot switch that lock, though it may still key a Profile Lookup Enrichment step. Differences in required data, screening, Enrichment, routing or Buyers do NOT split Workflows; different arrival paths do. Discover the actual channels before naming them, and never create a temporary umbrella Workflow ahead of that discovery. Never create one for a Profile-only catalog/history upload or merely to obtain an intake ID. Upserts on (org_id, code); call after the relevant profile_type_create. status is draft | active | paused | closed (defaults active on create); an explicit status is applied on create and update and never touches a deleted Workflow. inputValidationRules is the Intake payload allowlist AND presence enforcement; dedupeRules is the Workflow-local duplicate policy. Two rules decide whether this call is accepted: unknown top-level keys are REJECTED (a typo'd `allowedFields` does not silently pass), and any non-empty inputValidationRules must put at least one of the bound Profile Type's identifier fields in requiredFields — naming it only in optionalFields does not satisfy it, and an Intake that omits every identifier silently drops at missing_identifier. Read the identifiers with catalog_list_profile_types first. Full shapes, validators, and the deny-by-default re-entry table: the kontrolx-wizard skill, §Field reference.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1},"profileTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["draft","active","paused","closed"]},"inputValidationRules":{"type":"object","properties":{"requiredFields":{"type":"array","items":{"type":"string"}},"optionalFields":{"type":"array","items":{"type":"string"}},"validations":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"string"},"minLength":{"type":"integer","minimum":0,"maximum":9007199254740991},"maxLength":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"number"},"min":{"type":"number"},"max":{"type":"number"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"enum"},"values":{"readOnly":true,"type":"array","items":{"type":"string"}}},"required":["type","values"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"regex"},"pattern":{"type":"string"},"flags":{"type":"string"}},"required":["type","pattern"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"phone"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"file"},"maxBytes":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"object"}},"required":["type"],"additionalProperties":false}]}}},"required":["requiredFields"],"additionalProperties":false},"dedupeRules":{"type":"object","properties":{"windowDays":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"reentry":{"type":"object","properties":{"rejected":{"type":"string","enum":["allow","deny"]},"disqualified":{"type":"string","enum":["allow","deny"]},"awaiting":{"type":"string","enum":["allow","deny"]},"stuck":{"type":"string","enum":["allow","deny"]}},"additionalProperties":false}},"additionalProperties":false}},"required":["code","name","profileTypeId"],"additionalProperties":false}},{"id":"workflow_update_rules","name":"workflow_update_rules","description":"Update only input_validation_rules and/or dedupe_rules on an existing real Workflow without restating the row. Use for its Intake validation or Workflow-local duplicate policy; it does not apply to Profile-only inventory/history. inputValidationRules is the Intake payload allowlist AND presence enforcement; dedupeRules is the Workflow-local duplicate policy. Two rules decide whether this call is accepted: unknown top-level keys are REJECTED (a typo'd `allowedFields` does not silently pass), and any non-empty inputValidationRules must put at least one of the bound Profile Type's identifier fields in requiredFields — naming it only in optionalFields does not satisfy it, and an Intake that omits every identifier silently drops at missing_identifier. Read the identifiers with catalog_list_profile_types first. Full shapes, validators, and the deny-by-default re-entry table: the kontrolx-wizard skill, §Field reference.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"inputValidationRules":{"type":"object","properties":{"requiredFields":{"type":"array","items":{"type":"string"}},"optionalFields":{"type":"array","items":{"type":"string"}},"validations":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"string"},"minLength":{"type":"integer","minimum":0,"maximum":9007199254740991},"maxLength":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"number"},"min":{"type":"number"},"max":{"type":"number"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"enum"},"values":{"readOnly":true,"type":"array","items":{"type":"string"}}},"required":["type","values"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"regex"},"pattern":{"type":"string"},"flags":{"type":"string"}},"required":["type","pattern"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"phone"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"file"},"maxBytes":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"object"}},"required":["type"],"additionalProperties":false}]}}},"required":["requiredFields"],"additionalProperties":false},"dedupeRules":{"type":"object","properties":{"windowDays":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"reentry":{"type":"object","properties":{"rejected":{"type":"string","enum":["allow","deny"]},"disqualified":{"type":"string","enum":["allow","deny"]},"awaiting":{"type":"string","enum":["allow","deny"]},"stuck":{"type":"string","enum":["allow","deny"]}},"additionalProperties":false}},"additionalProperties":false}},"required":["workflowId"],"additionalProperties":false}},{"id":"vendor_create","name":"vendor_create","description":"Create or update a real Vendor identity: a party that delivers business events into a chosen Workflow, performs Enrichment, or both. Upserts on (org_id, code). Defaults vendorType=source, isInternal=false. A Vendor is not required merely because Profile-only inventory was uploaded; create one only for a real delivering or enriching party.","tags":["vendor"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1},"vendorType":{"type":"string","enum":["source","enrichment","both"]},"isInternal":{"type":"boolean"}},"required":["code","name"],"additionalProperties":false}},{"id":"buyer_create","name":"buyer_create","description":"Create or update a Buyer directory row for a potential or completed Placement destination. This is the directory entry only — it places the Buyer on no Workflow. Per-Workflow routing (priority, weight, cap, price, filters, schedule, pause, payload mapping, screeners) lives in workflows.placement_shape.routing.buyers[] and is set with workflow_routing_configure, or one entry at a time with workflow_routing_update_buyer. Delivery config — how accepted Placements physically reach this Buyer — is set with buyer_delivery_configure and read with buyer_delivery_get. Do not create Buyers for Profile-only storage or a Workflow with no Placement.","tags":["buyer"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1},"billingEmail":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}},"required":["code","name"],"additionalProperties":false}},{"id":"buyer_delivery_get","name":"buyer_delivery_get","description":"Read a Buyer's placement delivery configuration: deliveryMode (webhook | email | both) and delivery_config (delivery url/auth/format, email recipient). deliveryMode 'webhook' means a plain HTTP request to the buyer's own URL — the buyer does NOT need to support webhooks or register a subscription; any API endpoint works. This is the PLACEMENT DELIVERY channel — separate from Event Webhooks (webhook_* tools), which are notification subscriptions.","tags":["buyer"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"buyerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["buyerId"],"additionalProperties":false}},{"id":"buyer_delivery_configure","name":"buyer_delivery_configure","description":"Set a Buyer's placement delivery channel — how accepted placements physically reach them. deliveryMode webhook | email | both. 'webhook' is a misnomer kept for compatibility: it is a plain HTTP request to whatever URL the buyer gives you, so a buyer that 'does not support webhooks' but has an API is still deliveryMode webhook. Never reach for a Trigger to post leads to a buyer — Triggers are org event side-effects and carry no placement lifecycle, retry, or routing. Delivery config is environment-LOCAL: it does not travel sandbox→live, so set it per environment, and it is a separate system from Event Webhooks. Wire formats (json | form | query | raw + body_template) and where the field names come from: the kontrolx-wizard skill, §Field reference.","tags":["buyer"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"buyerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deliveryMode":{"type":"string","enum":["webhook","email","both"]},"deliveryConfig":{"type":"object","properties":{"webhook":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"auth_header":{"description":"Sent verbatim as the Authorization header.","type":"string"},"format":{"description":"Wire format the buyer endpoint requires. json (default) = application/json POST; form = application/x-www-form-urlencoded POST (classic lead-post endpoints like CallShaper /lead/post/<postkey> that reject JSON); query = GET with the mapped fields as query params, no body; raw = POST body_template with content_type (XML, plain text, any custom format).","type":"string","enum":["json","form","query","raw"]},"body_template":{"description":"raw format only — template with {{field}} placeholders resolved against the buyer's mapped payload, e.g. '<lead><phone>{{phone}}</phone></lead>'.","type":"string","maxLength":16384},"content_type":{"description":"raw format only — Content-Type header, default text/plain.","type":"string","maxLength":256}},"required":["url"],"additionalProperties":false},"email":{"type":"object","properties":{"to":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"cc":{"type":"array","items":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}}},"required":["to"],"additionalProperties":false}},"additionalProperties":false}},"required":["buyerId","deliveryMode","deliveryConfig"],"additionalProperties":false}},{"id":"workflow_routing_configure","name":"workflow_routing_configure","description":"Configure a real Workflow's Placement routing: REPLACES requiredIntakeFields, requiredEnrichmentTypes, defaultPriceCents, and routing.buyers[] in one call. Never call this for a Profile-only catalog upload or to manufacture an Intake. Call after workflow_create and, only when Placements apply, buyer_create. payloadMapping must be {fields:[{kind:\"field\",target,source,default?}|{kind:\"literal\",target,value}]} — a flat key/value map is REJECTED. \"target\" is written verbatim: a dot in it is a literal character, never a nesting separator. \"source\" (field rows only) is likewise a flat lookup key with no dotted traversal. The addressable source catalog, worked examples, and default/omit behaviour: the kontrolx-wizard skill, §Field reference. Reformatting a field is a declarative \"transform\" on the field row, and that is the ONLY way — there is no scripted step to write instead. Catalog and fallback behaviour: the kontrolx-wizard skill, §Field reference.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"defaultPriceCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"requiredIntakeFields":{"type":"array","items":{"type":"string"}},"requiredEnrichmentTypes":{"type":"array","items":{"type":"string"}},"mode":{"description":"How the next buyer is chosen from those eligible: priority (highest priority wins, the default), weighted (volume split in proportion to weight), round_robin (whoever has waited longest). Eligibility is separate and always applies — paused, outside schedule, filtered out, screened out, over cap.","type":"string","enum":["priority","weighted","round_robin"]},"buyers":{"type":"array","items":{"type":"object","properties":{"priority":{"description":"Higher is offered the lead first in priority mode.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weight":{"description":"Share of volume in weighted mode. Ignored by the other modes; absent is 1.","type":"integer","minimum":1,"maximum":1000},"cap":{"description":"Most leads this buyer takes in a period, counted in the buyer timezone. A buyer at its cap is skipped in every mode and the lead goes to the next one, rather than being held. limit 0 means no cap.","type":"object","properties":{"period":{"type":"string","enum":["day","week","month"]},"limit":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["period","limit"],"additionalProperties":false},"priceCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string","minLength":3,"maxLength":3},"filters":{"type":"object","propertyNames":{"type":"string","minLength":1},"additionalProperties":{}},"pausedAt":{"description":"ISO timestamp pauses this buyer ON THIS WORKFLOW; null resumes. The buyer row has its own cross-workflow pause.","anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},{"type":"null"}]},"schedule":{"description":"When this buyer accepts leads ON THIS WORKFLOW: { tz: IANA zone, windows: [{ days: [\"mon\"…], start: \"09:00\", end: \"17:00\" }] }. Outside every window the buyer is skipped and the lead goes to the next one. null inherits the buyer’s own schedule; an empty windows array is always open. A window may not cross midnight — split it into two.","anyOf":[{"type":"object","properties":{"tz":{"type":"string"},"windows":{"type":"array","items":{"type":"object","properties":{"days":{"minItems":1,"type":"array","items":{"type":"string","enum":["sun","mon","tue","wed","thu","fri","sat"]}},"start":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"end":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["days","start","end"],"additionalProperties":false}}},"required":["tz","windows"],"additionalProperties":false},{"type":"null"}]},"payloadMapping":{"type":"object","properties":{"fields":{"maxItems":200,"type":"array","items":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"field"},"target":{"type":"string","minLength":1},"source":{"type":"string","minLength":1},"default":{"type":["string","number","boolean","null"]},"transform":{"anyOf":[{"type":"string","enum":["trim","upper","lower","digits","phone10","nospace","yesno","date:YYYY-MM-DD","date:MM/DD/YYYY"]},{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"phone"},"style":{"type":"string","enum":["digits10","e164","pretty","digits"]}},"required":["kind","style"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"pattern":{"type":"string","minLength":1,"maxLength":32}},"required":["kind","pattern"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":200},"replaceWith":{"default":"","type":"string","maxLength":200},"regex":{"default":false,"type":"boolean"},"all":{"default":true,"type":"boolean"},"ignoreCase":{"default":false,"type":"boolean"}},"required":["kind","find","replaceWith","regex","all","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"extract"},"pattern":{"type":"string","minLength":1,"maxLength":200},"group":{"default":0,"type":"integer","minimum":0,"maximum":20}},"required":["kind","pattern","group"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"fallback":{"type":"string"},"ignoreCase":{"default":true,"type":"boolean"}},"required":["kind","values","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"template"},"pattern":{"type":"string","minLength":1,"maxLength":400}},"required":["kind","pattern"],"additionalProperties":false}]}]}},"required":["kind","target","source"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"literal"},"target":{"type":"string","minLength":1},"value":{"type":["string","number","boolean","null"]},"transform":{"anyOf":[{"type":"string","enum":["trim","upper","lower","digits","phone10","nospace","yesno","date:YYYY-MM-DD","date:MM/DD/YYYY"]},{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"phone"},"style":{"type":"string","enum":["digits10","e164","pretty","digits"]}},"required":["kind","style"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"pattern":{"type":"string","minLength":1,"maxLength":32}},"required":["kind","pattern"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":200},"replaceWith":{"default":"","type":"string","maxLength":200},"regex":{"default":false,"type":"boolean"},"all":{"default":true,"type":"boolean"},"ignoreCase":{"default":false,"type":"boolean"}},"required":["kind","find","replaceWith","regex","all","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"extract"},"pattern":{"type":"string","minLength":1,"maxLength":200},"group":{"default":0,"type":"integer","minimum":0,"maximum":20}},"required":["kind","pattern","group"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"fallback":{"type":"string"},"ignoreCase":{"default":true,"type":"boolean"}},"required":["kind","values","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"template"},"pattern":{"type":"string","minLength":1,"maxLength":400}},"required":["kind","pattern"],"additionalProperties":false}]}]}},"required":["kind","target","value"],"additionalProperties":false}]}}},"required":["fields"],"additionalProperties":false},"screeners":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["kind"],"additionalProperties":false}},"buyerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["buyerId"],"additionalProperties":false}}},"required":["workflowId","buyers"],"additionalProperties":false}},{"id":"workflow_routing_update_buyer","name":"workflow_routing_update_buyer","description":"Update ONE entry in workflows.placement_shape.routing.buyers[] without restating the entire array. Use to tweak a buyer's priority, payload mapping, or screeners post-onboarding. Throws if the buyerId is not currently in the workflow routing. This is an A+E+P Placement-routing operation, not Profile-only configuration. payloadMapping must be {fields:[{kind:\"field\",target,source,default?}|{kind:\"literal\",target,value}]} — a flat key/value map is REJECTED. \"target\" is written verbatim: a dot in it is a literal character, never a nesting separator. \"source\" (field rows only) is likewise a flat lookup key with no dotted traversal. The addressable source catalog, worked examples, and default/omit behaviour: the kontrolx-wizard skill, §Field reference. Reformatting a field is a declarative \"transform\" on the field row, and that is the ONLY way — there is no scripted step to write instead. Catalog and fallback behaviour: the kontrolx-wizard skill, §Field reference.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"buyerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"patch":{"type":"object","properties":{"priority":{"description":"Higher is offered the lead first in priority mode.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"weight":{"description":"Share of volume in weighted mode. Ignored by the other modes; absent is 1.","type":"integer","minimum":1,"maximum":1000},"cap":{"description":"Most leads this buyer takes in a period, counted in the buyer timezone. A buyer at its cap is skipped in every mode and the lead goes to the next one, rather than being held. limit 0 means no cap.","type":"object","properties":{"period":{"type":"string","enum":["day","week","month"]},"limit":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["period","limit"],"additionalProperties":false},"priceCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string","minLength":3,"maxLength":3},"filters":{"type":"object","propertyNames":{"type":"string","minLength":1},"additionalProperties":{}},"pausedAt":{"description":"ISO timestamp pauses this buyer ON THIS WORKFLOW; null resumes. The buyer row has its own cross-workflow pause.","anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},{"type":"null"}]},"schedule":{"description":"When this buyer accepts leads ON THIS WORKFLOW: { tz: IANA zone, windows: [{ days: [\"mon\"…], start: \"09:00\", end: \"17:00\" }] }. Outside every window the buyer is skipped and the lead goes to the next one. null inherits the buyer’s own schedule; an empty windows array is always open. A window may not cross midnight — split it into two.","anyOf":[{"type":"object","properties":{"tz":{"type":"string"},"windows":{"type":"array","items":{"type":"object","properties":{"days":{"minItems":1,"type":"array","items":{"type":"string","enum":["sun","mon","tue","wed","thu","fri","sat"]}},"start":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"end":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["days","start","end"],"additionalProperties":false}}},"required":["tz","windows"],"additionalProperties":false},{"type":"null"}]},"payloadMapping":{"type":"object","properties":{"fields":{"maxItems":200,"type":"array","items":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"field"},"target":{"type":"string","minLength":1},"source":{"type":"string","minLength":1},"default":{"type":["string","number","boolean","null"]},"transform":{"anyOf":[{"type":"string","enum":["trim","upper","lower","digits","phone10","nospace","yesno","date:YYYY-MM-DD","date:MM/DD/YYYY"]},{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"phone"},"style":{"type":"string","enum":["digits10","e164","pretty","digits"]}},"required":["kind","style"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"pattern":{"type":"string","minLength":1,"maxLength":32}},"required":["kind","pattern"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":200},"replaceWith":{"default":"","type":"string","maxLength":200},"regex":{"default":false,"type":"boolean"},"all":{"default":true,"type":"boolean"},"ignoreCase":{"default":false,"type":"boolean"}},"required":["kind","find","replaceWith","regex","all","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"extract"},"pattern":{"type":"string","minLength":1,"maxLength":200},"group":{"default":0,"type":"integer","minimum":0,"maximum":20}},"required":["kind","pattern","group"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"fallback":{"type":"string"},"ignoreCase":{"default":true,"type":"boolean"}},"required":["kind","values","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"template"},"pattern":{"type":"string","minLength":1,"maxLength":400}},"required":["kind","pattern"],"additionalProperties":false}]}]}},"required":["kind","target","source"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"literal"},"target":{"type":"string","minLength":1},"value":{"type":["string","number","boolean","null"]},"transform":{"anyOf":[{"type":"string","enum":["trim","upper","lower","digits","phone10","nospace","yesno","date:YYYY-MM-DD","date:MM/DD/YYYY"]},{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"phone"},"style":{"type":"string","enum":["digits10","e164","pretty","digits"]}},"required":["kind","style"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"pattern":{"type":"string","minLength":1,"maxLength":32}},"required":["kind","pattern"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":200},"replaceWith":{"default":"","type":"string","maxLength":200},"regex":{"default":false,"type":"boolean"},"all":{"default":true,"type":"boolean"},"ignoreCase":{"default":false,"type":"boolean"}},"required":["kind","find","replaceWith","regex","all","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"extract"},"pattern":{"type":"string","minLength":1,"maxLength":200},"group":{"default":0,"type":"integer","minimum":0,"maximum":20}},"required":["kind","pattern","group"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"fallback":{"type":"string"},"ignoreCase":{"default":true,"type":"boolean"}},"required":["kind","values","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"template"},"pattern":{"type":"string","minLength":1,"maxLength":400}},"required":["kind","pattern"],"additionalProperties":false}]}]}},"required":["kind","target","value"],"additionalProperties":false}]}}},"required":["fields"],"additionalProperties":false},"screeners":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["kind"],"additionalProperties":false}}},"additionalProperties":false}},"required":["workflowId","buyerId","patch"],"additionalProperties":false}},{"id":"workflow_screener_pipeline_configure","name":"workflow_screener_pipeline_configure","description":"Wire screener_types into a real Workflow — global codes (blacklist, input_validation, duplicate_control) and this org's custom screener types both resolve. Screeners run in WAVES: pass `waves` as [{codes, rule}] to say what runs together, where rule is 'all' (every member must pass — what a flat list does) or 'any' (one passing member carries the wave, which is how \"ask three vendors and take the lead if any will have it\" is written; as separate waves it refuses the moment the first says no). Every member of an `any` wave is called every time. A flat `screenerCodes` list is one screener per wave, in the order given. REPLACES that Workflow pipeline and throws if a code is missing — call catalog_get_workflow_screener_steps FIRST, or the steps you omit, their operator-set config, and their waves are dropped. Each code may appear AT MOST ONCE (unique per workflow+type). Returns { inserted, steps: [{ id, code, orderIndex }] }. Screening applies to arriving Intakes; it is not part of Profile-only inventory/history.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"screenerCodes":{"type":"array","items":{"type":"string","minLength":1},"description":"One screener per position, in order. The flat form; use `waves` to group."},"waves":{"description":"Screeners grouped into waves. Members of a wave run at the same time and the rule decides the verdict: all (every member must pass, the default) or any (one acceptance carries the wave — how \"ask three vendors and take the lead if any will have it\" is written). Wins over screenerCodes when both are given. A wave of one behaves identically under either rule.","type":"array","items":{"type":"object","properties":{"codes":{"minItems":1,"type":"array","items":{"type":"string","minLength":1}},"rule":{"type":"string","enum":["all","any"]}},"required":["codes"],"additionalProperties":false}}},"required":["workflowId","screenerCodes"],"additionalProperties":false}},{"id":"workflow_enrichment_pipeline_configure","name":"workflow_enrichment_pipeline_configure","description":"Configure Enrichments fixed to a real Workflow and its arriving Intakes: upsert types, then REPLACE workflow_enrichments. Steps run in WAVES, not in declaration order: give each step a `wave` (1-based) — steps sharing one run at the same time, and a wave waits for the wave before it. Omitting wave everywhere means everything fires at once. Call catalog_get_workflow_enrichment_steps first so an append does not wipe existing steps. This is for A+E or A+E+P Workflows, not Profile-only Enrichment.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"steps":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"target":{"type":"string","enum":["profile","intake"]},"integration":{"type":"object","properties":{"endpoint":{"type":"string","format":"uri"},"missionInstructions":{"type":"string","minLength":1},"profileLookup":{"type":"object","properties":{"match":{"type":"object","properties":{"fromPayloadPath":{"type":"string","minLength":1},"profileTypeCode":{"type":"string","minLength":1},"identifierType":{"type":"string","minLength":1}},"required":["fromPayloadPath","profileTypeCode","identifierType"],"additionalProperties":false},"pull":{"minItems":1,"type":"array","items":{"type":"string","minLength":1}},"maxAgeDays":{"type":"integer","exclusiveMinimum":0,"maximum":36500},"skipEnrichmentCodes":{"default":[],"type":"array","items":{"type":"string","minLength":1}}},"required":["match","pull","maxAgeDays","skipEnrichmentCodes"],"additionalProperties":false},"knowledge":{"type":"object","properties":{"kbId":{"type":"string","minLength":1},"questionFromPath":{"type":"string","minLength":1},"limit":{"default":6,"type":"integer","minimum":1,"maximum":20}},"required":["kbId","questionFromPath","limit"],"additionalProperties":false},"method":{"type":"string","enum":["GET","POST"]},"format":{"type":"string","enum":["json","form","raw"]},"bodyTemplate":{"type":"string","maxLength":16384},"contentType":{"type":"string","maxLength":256},"inputFields":{"default":[],"type":"array","items":{"anyOf":[{"type":"string","minLength":1},{"type":"object","properties":{"key":{"type":"string","minLength":1},"kind":{"type":"string","enum":["field","literal"]},"source":{"type":"string"},"transform":{"anyOf":[{"type":"string","enum":["trim","upper","lower","digits","phone10","nospace","yesno","date:YYYY-MM-DD","date:MM/DD/YYYY"]},{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"phone"},"style":{"type":"string","enum":["digits10","e164","pretty","digits"]}},"required":["kind","style"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"pattern":{"type":"string","minLength":1,"maxLength":32}},"required":["kind","pattern"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":200},"replaceWith":{"default":"","type":"string","maxLength":200},"regex":{"default":false,"type":"boolean"},"all":{"default":true,"type":"boolean"},"ignoreCase":{"default":false,"type":"boolean"}},"required":["kind","find","replaceWith","regex","all","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"extract"},"pattern":{"type":"string","minLength":1,"maxLength":200},"group":{"default":0,"type":"integer","minimum":0,"maximum":20}},"required":["kind","pattern","group"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"fallback":{"type":"string"},"ignoreCase":{"default":true,"type":"boolean"}},"required":["kind","values","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"template"},"pattern":{"type":"string","minLength":1,"maxLength":400}},"required":["kind","pattern"],"additionalProperties":false}]}]}},"required":["key","kind","source"],"additionalProperties":false}]}},"asyncMode":{"type":"boolean"},"timeoutMs":{"type":"integer","exclusiveMinimum":0,"maximum":60000},"failMode":{"type":"string","enum":["soft","hard"]},"attempts":{"type":"integer","minimum":1,"maximum":5},"authMode":{"type":"string","enum":["none","bearer","basic","raw"]},"authHeaderName":{"type":"string"},"authEnvVar":{"type":"string"},"headers":{"type":"object","propertyNames":{"type":"string","maxLength":128},"additionalProperties":{"type":"string","maxLength":2048}},"sendCallbackFields":{"type":"boolean"},"callbackFields":{"maxItems":3,"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["enrichment_id","callback_url","entry_url"]},"key":{"type":"string","minLength":1,"maxLength":128}},"required":["field","key"],"additionalProperties":false}}},"required":["inputFields"],"additionalProperties":false,"description":"Full vendor integration config. endpoint: absolute URL of the vendor endpoint. inputFields: what to send — each entry is { key: string, kind: \"field\"|\"literal\", source: string, transform?: string }. Reformatting a field is a declarative \"transform\" on the field row, and that is the ONLY way — there is no scripted step to write instead. Catalog and fallback behaviour: the kontrolx-wizard skill, §Field reference. kind=\"field\" resolves source as a dot-path into the intake payload or profile column (e.g. \"identifiers.phone.0\"). kind=\"literal\" sends source verbatim (good for vendor constants like type:\"check\"). key is the parameter name sent to the vendor. authMode: how to apply the vendor credential (bearer | basic | raw | none). The secret is stored encrypted in the DB — never in the integration config. timeoutMs: per-step timeout override in ms (max 60000, default 5000). failMode: \"soft\" (default) = mark step skipped and continue pipeline; \"hard\" = mark failed, downstream deps also skip."},"requiredPaths":{"type":"array","items":{"type":"string"}},"schema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"wave":{"description":"Which wave this step runs in, 1-based. Steps sharing a wave run at the SAME TIME; a wave waits for every step in the wave before it. Absent means wave 1 — so steps that all omit it fire together, which is what this call has always done. Declaring waves is the only way to say \"then\": execution reads the dependency each step waits on, and declaration order alone has never decided anything.","type":"integer","minimum":1,"maximum":9007199254740991}},"required":["code","name","target","integration"],"additionalProperties":false}}},"required":["workflowId","steps"],"additionalProperties":false}},{"id":"enrichment_type_create","name":"enrichment_type_create","description":"Create or update a standalone Enrichment type (a governed data integration) without attaching it to a Workflow. Upserts on (org, code). Catalog metadata ONLY: execution needs attachment to a real Workflow pipeline, or the operator-run Profile Type bulk path this surface cannot configure, trigger or poll — never invent a tool, Workflow or Intake to bridge that gap. `integration` carries the whole call: endpoint/method/inputFields, the body encoding (format json|form|raw, with bodyTemplate + contentType for raw), any fixed `headers` the vendor wants alongside the credential, and authMode (bearer/basic/raw/none) from the vendor's scheme. An ASYNC type also sends the return path — `callback_url`, `entry_url`, `enrichment_id` — because a vendor answering later cannot without it; a SYNC type sends none of it, since the answer comes back in the response. Override per field with `callbackFields: [{field, key}]` to rename a key the vendor spells differently, to drop one, or to give a sync vendor just `enrichment_id` as a correlation id. A broken call FAILS THE STEP by default (`failMode: 'soft'` lets the lead carry on without the data instead). `attempts` (1-5, default 1) retries a transport blip or a 5xx; a 4xx is never retried. THE SECRET IS NOT SET HERE and must never be asked for or accepted in chat — the operator enters it on that enrichment's connection step (/admin/enrichments); `navigate` them there. enrichment_test needs a real existing Intake and must never be unlocked with a synthetic one. If a unit cost is configured, disclose count × unit cost and get approval. Building one end to end: the build-enrichment skill.","tags":["enrichment"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1},"target":{"type":"string","enum":["profile","intake"]},"integration":{"type":"object","properties":{"endpoint":{"type":"string","format":"uri"},"missionInstructions":{"type":"string","minLength":1},"profileLookup":{"type":"object","properties":{"match":{"type":"object","properties":{"fromPayloadPath":{"type":"string","minLength":1},"profileTypeCode":{"type":"string","minLength":1},"identifierType":{"type":"string","minLength":1}},"required":["fromPayloadPath","profileTypeCode","identifierType"],"additionalProperties":false},"pull":{"minItems":1,"type":"array","items":{"type":"string","minLength":1}},"maxAgeDays":{"type":"integer","exclusiveMinimum":0,"maximum":36500},"skipEnrichmentCodes":{"default":[],"type":"array","items":{"type":"string","minLength":1}}},"required":["match","pull","maxAgeDays","skipEnrichmentCodes"],"additionalProperties":false},"knowledge":{"type":"object","properties":{"kbId":{"type":"string","minLength":1},"questionFromPath":{"type":"string","minLength":1},"limit":{"default":6,"type":"integer","minimum":1,"maximum":20}},"required":["kbId","questionFromPath","limit"],"additionalProperties":false},"method":{"type":"string","enum":["GET","POST"]},"format":{"type":"string","enum":["json","form","raw"]},"bodyTemplate":{"type":"string","maxLength":16384},"contentType":{"type":"string","maxLength":256},"inputFields":{"default":[],"type":"array","items":{"anyOf":[{"type":"string","minLength":1},{"type":"object","properties":{"key":{"type":"string","minLength":1},"kind":{"type":"string","enum":["field","literal"]},"source":{"type":"string"},"transform":{"anyOf":[{"type":"string","enum":["trim","upper","lower","digits","phone10","nospace","yesno","date:YYYY-MM-DD","date:MM/DD/YYYY"]},{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"phone"},"style":{"type":"string","enum":["digits10","e164","pretty","digits"]}},"required":["kind","style"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"pattern":{"type":"string","minLength":1,"maxLength":32}},"required":["kind","pattern"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":200},"replaceWith":{"default":"","type":"string","maxLength":200},"regex":{"default":false,"type":"boolean"},"all":{"default":true,"type":"boolean"},"ignoreCase":{"default":false,"type":"boolean"}},"required":["kind","find","replaceWith","regex","all","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"extract"},"pattern":{"type":"string","minLength":1,"maxLength":200},"group":{"default":0,"type":"integer","minimum":0,"maximum":20}},"required":["kind","pattern","group"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"fallback":{"type":"string"},"ignoreCase":{"default":true,"type":"boolean"}},"required":["kind","values","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"template"},"pattern":{"type":"string","minLength":1,"maxLength":400}},"required":["kind","pattern"],"additionalProperties":false}]}]}},"required":["key","kind","source"],"additionalProperties":false}]}},"asyncMode":{"type":"boolean"},"timeoutMs":{"type":"integer","exclusiveMinimum":0,"maximum":60000},"failMode":{"type":"string","enum":["soft","hard"]},"attempts":{"type":"integer","minimum":1,"maximum":5},"authMode":{"type":"string","enum":["none","bearer","basic","raw"]},"authHeaderName":{"type":"string"},"authEnvVar":{"type":"string"},"headers":{"type":"object","propertyNames":{"type":"string","maxLength":128},"additionalProperties":{"type":"string","maxLength":2048}},"sendCallbackFields":{"type":"boolean"},"callbackFields":{"maxItems":3,"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["enrichment_id","callback_url","entry_url"]},"key":{"type":"string","minLength":1,"maxLength":128}},"required":["field","key"],"additionalProperties":false}}},"required":["inputFields"],"additionalProperties":false,"description":"Full vendor integration config. endpoint: absolute URL of the vendor endpoint. inputFields: what to send — each entry is { key: string, kind: \"field\"|\"literal\", source: string }. kind=\"field\" resolves source as a dot-path into the intake payload or profile column (e.g. \"identifiers.phone.0\"). kind=\"literal\" sends source verbatim (good for vendor constants like type:\"check\"). key is the parameter name sent to the vendor. authMode: how to apply the vendor credential (bearer | basic | raw | none). The secret is stored encrypted in the DB — never in the integration config. timeoutMs: per-step timeout override in ms (max 60000, default 5000). failMode: \"soft\" (default) = mark step skipped and continue pipeline; \"hard\" = mark failed, downstream deps also skip."},"schema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"requiredPaths":{"type":"array","items":{"type":"string"}},"costCents":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["code","name","target","integration"],"additionalProperties":false}},{"id":"workflow_screener_config_set","name":"workflow_screener_config_set","description":"Set the per-Workflow config (jsonb) for one screener step, identified by its workflow_screener id (NOT the Workflow id — get it from workflow_screener_pipeline_configure / the Workflow screeners screen). Primary use is the duplicate_control re-entry policy: { windowDays: number, reentry: { rejected, disqualified, awaiting, stuck: 'allow' | 'deny' } } — windowDays bounds the dedupe lock; reentry decides, per the Profile's prior Intake status, whether a repeat event may re-enter (DEFAULT DENY for any status you omit). When the target step is duplicate_control the config is validated and rejected if malformed; other screeners take opaque jsonb config. Org-scoped. This applies only to a real Workflow that wires the screener, not Profile-only inventory/history.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowScreenerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["workflowScreenerId","config"],"additionalProperties":false}},{"id":"workflow_lifecycle_configure","name":"workflow_lifecycle_configure","description":"Declaratively define a Workflow's lifecycle state machine: REPLACES all states and transitions for that Workflow in one transaction. Custom state codes are fully supported — the standard intake→discovery→motion→trial→closed machine is only a default, and multiple terminal states (e.g. won + lost, or sold + returned) are legal. Call workflow_lifecycle_get FIRST and resend the full machine — a partial payload wipes whatever you omit. Rules: exactly one state has isInitial (intakes auto-open lifecycles there); every transition must reference declared codes; states that open lifecycles currently sit in cannot be dropped (transition or close those lifecycles first). Set manualAllowed: true on any transition you want to drive via lifecycle_transition; transitions default to auto-only. Config changes propagate to running intake pipelines within ~30s.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Target Workflow. From catalog_list_workflows[*].id."},"states":{"minItems":1,"type":"array","items":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":64,"description":"State code used by lifecycle_transition/lifecycle_list, e.g. 'sold'."},"name":{"type":"string","minLength":1,"description":"Human label, e.g. 'Sold'."},"isInitial":{"description":"Exactly one state must set this — new lifecycles open here.","type":"boolean"},"isTerminal":{"description":"Transitioning into this state CLOSES the lifecycle. Multiple terminals allowed (won/lost).","type":"boolean"}},"required":["code","name"],"additionalProperties":false},"description":"Full ordered state list; array order becomes display order."},"transitions":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","minLength":1,"description":"Declared state code the transition leaves."},"to":{"type":"string","minLength":1,"description":"Declared state code the transition enters."},"manualAllowed":{"description":"true = lifecycle_transition (and the admin UI) may drive this edge. Default false (auto-only).","type":"boolean"},"autoEvent":{"description":"Optional platform event that fires this edge automatically, e.g. 'intake.qualified'. Omit for manual-only edges.","type":"string"}},"required":["from","to"],"additionalProperties":false},"description":"Full legal-edge list. Anything not listed is an illegal transition."}},"required":["workflowId","states","transitions"],"additionalProperties":false}},{"id":"workflow_lifecycle_get","name":"workflow_lifecycle_get","description":"Read a Workflow's lifecycle state machine definition: states (code, name, orderIndex, isInitial, isTerminal) and transitions (from, to, manualAllowed, autoEvent). Empty arrays mean the Workflow has no machine and intakes will not open lifecycles. Always call this before workflow_lifecycle_configure — configure REPLACES the whole machine.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Target Workflow. From catalog_list_workflows[*].id."}},"required":["workflowId"],"additionalProperties":false}},{"id":"workflow_intent_set","name":"workflow_intent_set","description":"State what happens to a lead that PASSED screening: 'enrich' (run this Workflow's enrichments, then offer it to buyers), 'enrich_capture' (run the enrichments, then keep the profile — no buyer, by choice), 'place' (straight to buyers, no enrichment), or 'capture' (keep the profile and stop — no buyer, by choice). null means follow the setup, deriving the answer from whether buyers happen to be attached. Set it whenever a Workflow is meant to keep leads rather than sell them: without it, a Workflow that deliberately sells nothing is indistinguishable from one whose buyers were never wired, and its setup reads as unfinished forever. Do NOT attach a buyer nobody asked for to make that go away.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"intent":{"anyOf":[{"type":"string","enum":["enrich","enrich_capture","place","capture"]},{"type":"null"}]}},"required":["workflowId","intent"],"additionalProperties":false}},{"id":"workflow_vendor_cost_defaults_set","name":"workflow_vendor_cost_defaults_set","description":"What this Workflow owes a vendor per lead, before any per-vendor override. Two moments carry a cost because two different things are being paid for: costOnQualifiedCents is owed when a lead passes screening (the vendor delivered something usable), costOnAcceptedCents when a buyer takes it. null means nothing is owed at that moment — distinct from 0, which is a stated free. A per-vendor figure set with workflow_vendor_set wins over this.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"costOnQualifiedCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"costOnAcceptedCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"currency":{"type":"string","minLength":3,"maxLength":3}},"required":["workflowId","costOnQualifiedCents","costOnAcceptedCents","currency"],"additionalProperties":false}},{"id":"workflow_vendor_set","name":"workflow_vendor_set","description":"Let a Vendor post into this Workflow, on its own terms. Creates the binding if it is absent and updates it otherwise. schedule limits WHEN this vendor may deliver here; paused stops it without losing the setup; the two cost fields override the Workflow's defaults for this vendor only. Omitting a field CLEARS it — send the whole set of terms you want, not a patch. This does NOT issue the vendor's API key: minting a credential is an operator action on the Workflow's Vendors screen, so direct them there once the binding exists.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"vendorId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"schedule":{"anyOf":[{"type":"object","properties":{"tz":{"type":"string"},"windows":{"type":"array","items":{"type":"object","properties":{"days":{"minItems":1,"type":"array","items":{"type":"string","enum":["sun","mon","tue","wed","thu","fri","sat"]}},"start":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"end":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["days","start","end"],"additionalProperties":false}}},"required":["tz","windows"],"additionalProperties":false},{"type":"null"}]},"paused":{"type":"boolean"},"pausedReason":{"type":["string","null"]},"costOnQualifiedCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"costOnAcceptedCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"costCurrency":{"anyOf":[{"type":"string","minLength":3,"maxLength":3},{"type":"null"}]}},"required":["workflowId","vendorId"],"additionalProperties":false}},{"id":"workflow_vendor_remove","name":"workflow_vendor_remove","description":"Stop a Vendor posting into this Workflow. The Vendor keeps existing — it may deliver into other Workflows, and everything it already delivered here stays attributed to it. Returns { removed: false } when there was no binding to remove.","tags":["workflow"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"vendorId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["workflowId","vendorId"],"additionalProperties":false}},{"id":"screener_type_create","name":"screener_type_create","description":"Define a screener this org does not have yet, so workflow_screener_pipeline_configure can wire it by code. That tool only RESOLVES codes — the built-ins (blacklist, input_validation, duplicate_control) and types already defined — so anything else has to be created here first. mode 'pre_ping' runs BOTH when a supplier pings and on the posted lead; 'post' only ever sees a posted lead. Set ownerWorkflowId so removing it from that pipeline leaves it offered back there and to no other Workflow. WHAT it asks and where it sends the request is configured afterwards on the screener's own page — a custom screener with nowhere to send its request cannot reach a verdict, and a screener that cannot answer REJECTS every lead, so say that plainly rather than leaving it wired and silent.","tags":["screener"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1},"description":{"type":["string","null"]},"mode":{"type":"string","enum":["pre_ping","post"]},"ownerWorkflowId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]}},"required":["code","name","mode"],"additionalProperties":false}},{"id":"enrichment_entry_pin_set","name":"enrichment_entry_pin_set","description":"Get the URL and PIN a HUMAN uses to answer an async enrichment by hand, issuing the PIN if there is none. Returns { code, pin, url }: the agent opens the url, types the pin, then the identifier of the lead they are answering for. Length is 4-6 digits (default 6) because someone reads it off a screen mid-call — it identifies WHICH enrichment is being answered, and the identifier that follows is what authorises the answer. replace: true issues a NEW one and is destructive: whoever holds the old number stops being able to answer, so confirm before using it.","tags":["enrichment"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"enrichmentTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"length":{"type":"integer","minimum":4,"maximum":6},"replace":{"type":"boolean"}},"required":["enrichmentTypeId"],"additionalProperties":false}},{"id":"enrichment_type_resubmit_policy_set","name":"enrichment_type_resubmit_policy_set","description":"Whether a vendor may send a SECOND result for an enrichment already answered, and for how long. allowResubmit false rejects any later submission. resubmitWindowHours null with allowResubmit true means no time limit; a number closes the window that many hours after the first result. Use it for vendors that correct their own answers, and leave it off for vendors whose first answer is final — an open window means a placed lead can change underneath a buyer who already paid for it.","tags":["enrichment"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"enrichmentTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"allowResubmit":{"type":"boolean"},"resubmitWindowHours":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]}},"required":["enrichmentTypeId","allowResubmit","resubmitWindowHours"],"additionalProperties":false}},{"id":"trigger_list","name":"trigger_list","description":"A Workflow's automations: what fires when a step of the line finishes. Returns each one's id, name, scope, event, target kind, and whether it is enabled. Read this before changing anything — an automation that is disabled is not the same as one that is absent.","tags":["trigger"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["workflowId"],"additionalProperties":false}},{"id":"trigger_create","name":"trigger_create","description":"Hang an automation off a step of a Workflow. scope says which step (intake, enrichment, placement, lifecycle) and event says what happened. It either POSTs to a URL (targetKind 'http' with an integration.endpoint) or runs one of this org's action types (targetKind 'action' with an actionTypeId) — never both; the database enforces exactly that. An org event side-effect is all this is: it carries no placement lifecycle, retry, or routing, so never reach for one to deliver a lead to a buyer.","tags":["trigger"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"scope":{"type":"string","enum":["intake","enrichment","placement","lifecycle"]},"event":{"type":"string","minLength":1,"maxLength":64},"eventFilter":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"targetKind":{"default":"http","type":"string","enum":["http","action"]},"actionTypeId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"integration":{"type":"object","properties":{"endpoint":{"type":"string","format":"uri"},"method":{"type":"string","enum":["GET","POST"]},"format":{"type":"string","enum":["json","form","raw","query"]},"bodyTemplate":{"type":"string","maxLength":16384},"contentType":{"type":"string","maxLength":256},"inputFields":{"default":[],"type":"array","items":{"anyOf":[{"type":"string","minLength":1},{"type":"object","properties":{"key":{"type":"string","minLength":1},"kind":{"type":"string","enum":["field","literal"]},"source":{"type":"string"}},"required":["key","kind","source"],"additionalProperties":false}]}},"authEnvVar":{"type":"string"},"signing":{"type":"object","properties":{"enabled":{"type":"boolean"},"secretEnv":{"type":"string"}},"required":["enabled","secretEnv"],"additionalProperties":false}},"required":["endpoint","inputFields"],"additionalProperties":false},"enabled":{"default":true,"type":"boolean"}},"required":["name","workflowId","scope","event","eventFilter","targetKind","enabled"],"additionalProperties":false}},{"id":"trigger_set_enabled","name":"trigger_set_enabled","description":"Turn one automation on or off. This is how a misbehaving automation is stopped without losing how it was set up — prefer it to trigger_delete unless the automation is genuinely unwanted.","tags":["trigger"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"triggerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"enabled":{"type":"boolean"}},"required":["triggerId","enabled"],"additionalProperties":false}},{"id":"trigger_delete","name":"trigger_delete","description":"Remove an automation permanently. Its configuration is not recoverable; trigger_set_enabled false is the reversible way to stop one firing.","tags":["trigger"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"triggerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["triggerId"],"additionalProperties":false}},{"id":"sample_activity_generate","name":"sample_activity_generate","description":"Generate fake activity through a confirmed real Workflow pipeline. Opens a sample_run and tags every produced row with sample_run_id so sample_activity_purge removes exactly that run. speed 'realistic' (default) runs real ingestIntake, ~40-60s per 200 intakes; 'fast' bulk-inserts in ~3s. Requires >=1 workflow and vendor. Intakes round-robin across all org workflows unless workflowId routes them through one (it must belong to the org and not be soft-deleted). Does NOT run the alert evaluator. Never a reason to create a synthetic Workflow or Intake.","tags":["sample"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"days":{"type":"integer","exclusiveMinimum":0,"maximum":365},"count":{"type":"integer","exclusiveMinimum":0,"maximum":2000},"mix":{"type":"string","enum":["realistic","happy"]},"speed":{"type":"string","enum":["realistic","fast"]},"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"additionalProperties":false}},{"id":"sample_activity_purge","name":"sample_activity_purge","description":"Remove sample data previously generated for a real Workflow pipeline. If sampleRunId is provided: purge that batch only. If omitted: purge ALL sample runs in this org. Real customer rows (sample_run_id IS NULL) are never touched. Profiles that merged with real intakes mid-run survive with sample_run_id cleared. This tool is not part of Profile-only inventory/history setup.","tags":["sample"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"sampleRunId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"additionalProperties":false}},{"id":"search","name":"search","description":"Fuzzy, typo-tolerant search over the caller's org data. Returns hits grouped by kind: profile (people/companies by email, phone, name, or city), buyer / vendor / workflow (catalog entities by name or code; buyers also by billing email), and placement (by buyer_reference). intake and enrichment have no human-text columns, so they are resolved via PROFILE linkage — the query fuzzy-matches a profile and returns that profile's intakes / enrichments (id + status + profile label). Pass `kinds` to narrow the search (default = every kind your role may read); `limit` caps hits per kind (1-50, default 10). Each hit carries a relevance `score`, a display `label`, and kind-specific `fields`; `truncated[kind]` flags a kind that hit its limit. Results are ALWAYS limited to your org and to the kinds your read scopes permit.","tags":["search"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"q":{"type":"string","minLength":2,"maxLength":200},"kinds":{"type":"array","items":{"type":"string","enum":["profile","intake","enrichment","placement","buyer","vendor","workflow"]}},"limit":{"default":10,"type":"integer","minimum":1,"maximum":50}},"required":["q","limit"],"additionalProperties":false}},{"id":"org_current","name":"org_current","description":"Show which organization the current session is operating on. Returns the active org's id, name, slug, the caller's role in it, and the identity kind (session vs api-key). Use this first whenever an action is org-specific so you confirm the right org before acting.","tags":["org"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{},"additionalProperties":false}},{"id":"org_list","name":"org_list","description":"List the organizations the authenticated user belongs to, each with its id, name, slug, the user's role, and a `current` flag marking the org this session is bound to. To operate on a different org, reconnect / re-consent with that org active — a single session's token cannot switch orgs. For an api-key caller only the bound org is returned. Returns at most `limit` rows (default 100, hard cap 500); `truncated: true` marks a shortened answer.","tags":["org"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"limit":{"description":"Maximum rows returned. Default 100, hard cap 500.","type":"integer","minimum":1,"maximum":500}},"additionalProperties":false}},{"id":"capsule_catalog","name":"capsule_catalog","description":"Read the authorable capsule vocabulary scoped to your role: the catalog of Zero queries you MAY author (each with its min-role, allowed access modes, allowed columns, and metric vocabulary — dimensions/measures/filterable/temporal), the dataSource shapes (zero-query for auto-refreshing row data; metric for server-computed static aggregates with manual refresh), the 8 widget types and their required fields, and ready contractExamples. Capsules support two data paths: zero-query (auto-refreshing rows — counts/tables/selects) and metric (server-computed, STATIC — filtered counts, sums, averages, ratios, grouped by up to 3 dimensions). Use a metric dataSource for accept-rate, $ totals, and by-tier breakdowns — capsules are NOT limited to counting. Use this as the authoring reference BEFORE calling capsule_upsert. Pass `contract` to capsule_upsert as a JSON OBJECT, not a string.\n\nAUTH: Requires a customer_admin key (capsule:manage).","tags":["capsule"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{},"additionalProperties":false}},{"id":"capsule_upsert","name":"capsule_upsert","description":"Create or update a capsule (dashboard / form / tool) in your org. API-key-authored capsules are ORG-OWNED (no individual owner). The contract is validated against the server catalog — every zero-query data source must be catalogued and within your role's min-role + column allowlist; metric dataSources must use only dimensions/measures/filterable from the catalog (see capsule_catalog). Supports both zero-query (auto-refreshing rows) and metric (server-computed, STATIC — filtered counts/sums/averages/ratios grouped by up to 3 dimensions) data paths — capsules can compute accept-rate, $ totals, and by-tier breakdowns, not just counts. Returns { slug, status, visibility, url }.\n\nAUTH: Requires a customer_admin key (capsule:manage — publish allowed).","tags":["capsule"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"slug":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9-]+$"},"name":{"type":"string","minLength":1},"kind":{"type":"string","enum":["dashboard","form","tool"]},"access":{"type":"string","enum":["session","apikey","public"]},"status":{"type":"string","enum":["draft","published"]},"visibility":{"type":"string","enum":["org","private"]},"audience":{"type":"string","enum":["internal","buyer_portal","vendor_portal"]},"targetEntityId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"contract":{"type":"object","properties":{"dataSources":{"default":[],"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","const":"zero-query"},"query":{"type":"string","minLength":1}},"required":["id","type","query"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","const":"intake"},"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["id","type","workflowId"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","const":"metric"},"query":{"type":"string","minLength":1},"dimensions":{"maxItems":3,"type":"array","items":{"type":"string","minLength":1}},"measures":{"minItems":1,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"agg":{"type":"string","enum":["count","sum","avg","min","max","count_distinct"]},"col":{"type":"string","minLength":1},"filter":{"type":"object","properties":{"col":{"type":"string","minLength":1},"op":{"type":"string","enum":["eq","neq","in","gte","lte","between"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"array","items":{"type":["string","number"]}}]}},"required":["col","op","value"],"additionalProperties":false}},"required":["id","agg"],"additionalProperties":false}},"ratios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"numerator":{"anyOf":[{"type":"object","properties":{"col":{"type":"string","minLength":1},"op":{"type":"string","enum":["eq","neq","in","gte","lte","between"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"array","items":{"type":["string","number"]}}]}},"required":["col","op","value"],"additionalProperties":false},{"type":"object","properties":{"measure":{"type":"string","minLength":1}},"required":["measure"],"additionalProperties":false}]},"denominator":{"anyOf":[{"type":"object","properties":{"col":{"type":"string","minLength":1},"op":{"type":"string","enum":["eq","neq","in","gte","lte","between"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"array","items":{"type":["string","number"]}}]}},"required":["col","op","value"],"additionalProperties":false},{"type":"object","properties":{"measure":{"type":"string","minLength":1}},"required":["measure"],"additionalProperties":false}]}},"required":["id","numerator","denominator"],"additionalProperties":false}},"filters":{"type":"array","items":{"type":"object","properties":{"col":{"type":"string","minLength":1},"op":{"type":"string","enum":["eq","neq","in","gte","lte","between"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"array","items":{"type":["string","number"]}}]}},"required":["col","op","value"],"additionalProperties":false}}},"required":["id","type","query","measures"],"additionalProperties":false}]}},"widgets":{"minItems":1,"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"stat"},"title":{"type":"string"},"source":{"type":"string"},"measure":{"type":"string","minLength":1},"format":{"type":"string","enum":["number","currency","percent"]},"id":{"type":"string","minLength":1,"maxLength":64},"layout":{"type":"object","properties":{"size":{"type":"string","enum":["small","medium","large","full"]},"span":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"order":{"type":"integer","minimum":0,"maximum":9007199254740991},"section":{"type":"string","minLength":1,"maxLength":80}},"additionalProperties":false},"style":{"type":"object","properties":{"accent":{"default":"default","type":"string","enum":["default","emerald","violet","amber","rose","sky","slate"]}},"additionalProperties":false}},"required":["type","title","source"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"table"},"source":{"type":"string"},"columns":{"minItems":1,"type":"array","items":{"type":"string"}},"id":{"type":"string","minLength":1,"maxLength":64},"layout":{"type":"object","properties":{"size":{"type":"string","enum":["small","medium","large","full"]},"span":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"order":{"type":"integer","minimum":0,"maximum":9007199254740991},"section":{"type":"string","minLength":1,"maxLength":80}},"additionalProperties":false},"style":{"type":"object","properties":{"accent":{"default":"default","type":"string","enum":["default","emerald","violet","amber","rose","sky","slate"]}},"additionalProperties":false}},"required":["type","source","columns"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"form"},"source":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1},"label":{"type":"string","minLength":1},"type":{"type":"string","enum":["text","email","tel","number"]},"required":{"default":false,"type":"boolean"}},"required":["name","label","type","required"],"additionalProperties":false}},"id":{"type":"string","minLength":1,"maxLength":64},"layout":{"type":"object","properties":{"size":{"type":"string","enum":["small","medium","large","full"]},"span":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"order":{"type":"integer","minimum":0,"maximum":9007199254740991},"section":{"type":"string","minLength":1,"maxLength":80}},"additionalProperties":false},"style":{"type":"object","properties":{"accent":{"default":"default","type":"string","enum":["default","emerald","violet","amber","rose","sky","slate"]}},"additionalProperties":false}},"required":["type","source","fields"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"text"},"value":{"type":"string"},"id":{"type":"string","minLength":1,"maxLength":64},"layout":{"type":"object","properties":{"size":{"type":"string","enum":["small","medium","large","full"]},"span":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"order":{"type":"integer","minimum":0,"maximum":9007199254740991},"section":{"type":"string","minLength":1,"maxLength":80}},"additionalProperties":false},"style":{"type":"object","properties":{"accent":{"default":"default","type":"string","enum":["default","emerald","violet","amber","rose","sky","slate"]}},"additionalProperties":false}},"required":["type","value"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"chart"},"source":{"type":"string"},"x":{"type":"string"},"y":{"type":"string"},"kind":{"type":"string","enum":["line","bar","area","pie"]},"id":{"type":"string","minLength":1,"maxLength":64},"layout":{"type":"object","properties":{"size":{"type":"string","enum":["small","medium","large","full"]},"span":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"order":{"type":"integer","minimum":0,"maximum":9007199254740991},"section":{"type":"string","minLength":1,"maxLength":80}},"additionalProperties":false},"style":{"type":"object","properties":{"accent":{"default":"default","type":"string","enum":["default","emerald","violet","amber","rose","sky","slate"]}},"additionalProperties":false}},"required":["type","source","x","y","kind"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"select"},"source":{"type":"string"},"column":{"type":"string"},"label":{"type":"string"},"id":{"type":"string","minLength":1,"maxLength":64},"layout":{"type":"object","properties":{"size":{"type":"string","enum":["small","medium","large","full"]},"span":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"order":{"type":"integer","minimum":0,"maximum":9007199254740991},"section":{"type":"string","minLength":1,"maxLength":80}},"additionalProperties":false},"style":{"type":"object","properties":{"accent":{"default":"default","type":"string","enum":["default","emerald","violet","amber","rose","sky","slate"]}},"additionalProperties":false}},"required":["type","source","column","label"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"badge"},"title":{"type":"string"},"source":{"type":"string"},"measure":{"type":"string","minLength":1},"format":{"type":"string","enum":["number","currency","percent"]},"id":{"type":"string","minLength":1,"maxLength":64},"layout":{"type":"object","properties":{"size":{"type":"string","enum":["small","medium","large","full"]},"span":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"order":{"type":"integer","minimum":0,"maximum":9007199254740991},"section":{"type":"string","minLength":1,"maxLength":80}},"additionalProperties":false},"style":{"type":"object","properties":{"accent":{"default":"default","type":"string","enum":["default","emerald","violet","amber","rose","sky","slate"]}},"additionalProperties":false}},"required":["type","title","source"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"metric-table"},"source":{"type":"string"},"dimensions":{"minItems":1,"maxItems":3,"type":"array","items":{"type":"string","minLength":1}},"columns":{"minItems":1,"type":"array","items":{"type":"string","minLength":1}},"title":{"type":"string"},"id":{"type":"string","minLength":1,"maxLength":64},"layout":{"type":"object","properties":{"size":{"type":"string","enum":["small","medium","large","full"]},"span":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"order":{"type":"integer","minimum":0,"maximum":9007199254740991},"section":{"type":"string","minLength":1,"maxLength":80}},"additionalProperties":false},"style":{"type":"object","properties":{"accent":{"default":"default","type":"string","enum":["default","emerald","violet","amber","rose","sky","slate"]}},"additionalProperties":false}},"required":["type","source","dimensions","columns"],"additionalProperties":false}]}},"theme":{"default":"clean","type":"string","enum":["clean","midnight","slate","brand"]},"title":{"type":"string","minLength":1,"maxLength":120}},"required":["dataSources","widgets"],"additionalProperties":false}},"required":["slug","name","kind","access","contract"],"additionalProperties":false}},{"id":"capsule_compose","name":"capsule_compose","description":"Build a metric dashboard in ONE call: pass a structured intent — a catalogued `query`, optional `dimensions` (0-3 group-by), and full `measures` (each { id, agg, col?, filter? }) + optional `ratios` — and the SERVER generates the envelope and an auto-arranged widget layout (a stat per measure/ratio, plus a by-dimension metric-table), then persists it. Use capsule_catalog FIRST to see which queries/dimensions/measures your role may use; any column not in the catalog is REJECTED and nothing is saved (fail-closed). Omit `slug` to create a fresh capsule (a unique slug is generated); pass `slug` to update one you own. For live/reactive tiles or hand-arranged layouts use capsule_upsert. Set `audience` to 'buyer_portal' or 'vendor_portal' to publish the dashboard into the partner portal (data auto-scoped to each viewer); optionally `targetEntityId` to pin it to one buyer/vendor. Portal dashboards must use a portal-eligible query (buyer_portal→placements, vendor_portal→intakes_board) — see capsule_catalog. Returns { slug, status, visibility, url }.\n\nAUTH: Requires a customer_admin key (capsule:manage — publish allowed).","tags":["capsule"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":120},"query":{"type":"string","minLength":1},"dimensions":{"maxItems":3,"type":"array","items":{"type":"string","minLength":1}},"measures":{"minItems":1,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"agg":{"type":"string","enum":["count","sum","avg","min","max","count_distinct"]},"col":{"type":"string","minLength":1},"filter":{"type":"object","properties":{"col":{"type":"string","minLength":1},"op":{"type":"string","enum":["eq","neq","in","gte","lte","between"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"array","items":{"type":["string","number"]}}]}},"required":["col","op","value"],"additionalProperties":false}},"required":["id","agg"],"additionalProperties":false}},"ratios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"numerator":{"anyOf":[{"type":"object","properties":{"col":{"type":"string","minLength":1},"op":{"type":"string","enum":["eq","neq","in","gte","lte","between"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"array","items":{"type":["string","number"]}}]}},"required":["col","op","value"],"additionalProperties":false},{"type":"object","properties":{"measure":{"type":"string","minLength":1}},"required":["measure"],"additionalProperties":false}]},"denominator":{"anyOf":[{"type":"object","properties":{"col":{"type":"string","minLength":1},"op":{"type":"string","enum":["eq","neq","in","gte","lte","between"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"array","items":{"type":["string","number"]}}]}},"required":["col","op","value"],"additionalProperties":false},{"type":"object","properties":{"measure":{"type":"string","minLength":1}},"required":["measure"],"additionalProperties":false}]}},"required":["id","numerator","denominator"],"additionalProperties":false}},"filters":{"type":"array","items":{"type":"object","properties":{"col":{"type":"string","minLength":1},"op":{"type":"string","enum":["eq","neq","in","gte","lte","between"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"array","items":{"type":["string","number"]}}]}},"required":["col","op","value"],"additionalProperties":false}},"slug":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9-]+$"},"access":{"type":"string","enum":["session","apikey","public"]},"status":{"type":"string","enum":["draft","published"]},"visibility":{"type":"string","enum":["org","private"]},"audience":{"type":"string","enum":["internal","buyer_portal","vendor_portal"]},"targetEntityId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]}},"required":["title","query","measures"],"additionalProperties":false}},{"id":"capsule_list","name":"capsule_list","description":"List the capsules in your org (slug, name, kind, access, visibility, status). Use to discover existing capsules before editing one via capsule_upsert.\n\nAUTH: Requires a customer_admin key (capsule:manage).","tags":["capsule"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{},"additionalProperties":false}},{"id":"capsule_delete","name":"capsule_delete","description":"Permanently delete a capsule in your org by slug. You may delete a capsule you own or an org-owned (ownerless) one; deleting another member's personal capsule is denied. Destructive and irreversible.\n\nAUTH: Requires a customer_admin key (capsule:manage).","tags":["capsule"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"slug":{"type":"string","minLength":1}},"required":["slug"],"additionalProperties":false}},{"id":"capsule_patch","name":"capsule_patch","description":"Tweak ONE widget's layout/style without rebuilding the whole capsule — e.g. make a tile wider, reorder it, group it into a section, or recolor its accent. Locate the widget by its `id` (preferred) or 0-based `index`. Layout/style only; to change data/queries use capsule_upsert. Returns { slug, widgetId, applied }.\n\nAUTH: Requires a customer_admin key (capsule:manage).","tags":["capsule"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"slug":{"type":"string","minLength":1},"widgetId":{"type":"string","minLength":1},"index":{"type":"integer","minimum":0,"maximum":9007199254740991},"layout":{"type":"object","properties":{"size":{"type":"string","enum":["small","medium","large","full"]},"span":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"order":{"type":"integer","minimum":0,"maximum":9007199254740991},"section":{"type":"string","minLength":1,"maxLength":80}},"additionalProperties":false},"style":{"type":"object","properties":{"accent":{"type":"string","enum":["default","emerald","violet","amber","rose","sky","slate"]}},"additionalProperties":false}},"required":["slug"],"additionalProperties":false}},{"id":"alert_status","name":"alert_status","description":"List alert rules and recent firing activity for the org. Returns each rule with its config and how many times it fired in the last 24 h (firedLast24h), plus org-level totals (activeRuleCount, firingLast24h). Note: a rule is \"firing-eligible\" when isActive=true; actual firing is cooldown-gated by the evaluator — lastFiredAt and firedLast24h show recent activity.","tags":["alert"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{},"additionalProperties":false}},{"id":"system_status","name":"system_status","description":"Health summary for the org. Returns stuck/awaiting enrichments (org-scoped), failed webhook deliveries in the last 24 h (org-scoped), unrouted placements (org-scoped), and infra checks for db/redis (global, not per-org). The top-level ok flag is true only when all counts are zero and infra is healthy. Queue depth is intentionally not included here — use dedicated queue tooling if needed.","tags":["system"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{},"additionalProperties":false}},{"id":"org_readiness","name":"org_readiness","description":"Preflight diagnostics: is this org ready to run end-to-end? Returns checks[] with per-check status (pass/fail), a summary, a fixHint, and owner — who can fix it: platform_operator (server env, NOT fixable from the org side) or org_admin (org configuration). Current checks: encryption (can screener/enrichment vendor credentials be stored — fails when the platform ENCRYPTION_KEY is unset), email_transport (is platform email configured), buyer_delivery_config (active external buyers whose delivery config is missing/invalid for their delivery mode, with the failing buyers listed — these buyers fail every placement delivery; buyer delivery config is separate from Event Webhooks). Top-level ok is true only when every check passes. Re-run this instead of caching a past failure — platform state changes.","tags":["org"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{},"additionalProperties":false}},{"id":"call_agent","name":"call_agent","description":"Call a CONFIGURED external A2A agent by name. Pass the peer `agent` name (admin-configured; see call_agent's error for the available list), the remote `skill` (a tool the peer exposes), and optional `input`. Peer URLs + credentials live server-side — you only name the agent, never a URL or key. Returns the peer's result.\n\nAUTH: Requires config:manage (customer_admin).","tags":["call"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"agent":{"type":"string","minLength":1},"skill":{"type":"string","minLength":1},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["agent","skill"],"additionalProperties":false}},{"id":"blacklist_entry_list","name":"blacklist_entry_list","description":"List active blacklist entries for one profile type (org-scoped, paginated 50 per page; pass page=0,1,2,…). The blacklist is PER-PROFILE-TYPE: profileTypeId is REQUIRED and only that type's entries are returned. The blacklist screener rejects any intake of that profile type whose profile identifier matches an active entry. Returns { entries, page, pageSize }; each entry carries identifierType, identifierValue, reason, notes, addedAt and expiresAt. Optional `search` substring-matches identifierValue. Read-only.","tags":["blacklist"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"search":{"type":"string"},"page":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["profileTypeId"],"additionalProperties":false}},{"id":"blacklist_entry_add","name":"blacklist_entry_add","description":"Add one blacklist entry for a profile type (the blacklist is PER-PROFILE-TYPE). Once added, the blacklist screener rejects any future intake OF THAT TYPE whose profile identifier matches identifierType+identifierValue. profileTypeId is REQUIRED and identifierType must be one of that profile type's configured identifiers — otherwise the call is rejected. Idempotent: a duplicate (org, profileType, identifierType, identifierValue) is a no-op. `expiresAt` (ISO-8601) optionally time-boxes the entry; `reason`/`notes` are free text. Returns { ok: true }.","tags":["blacklist"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"identifierType":{"type":"string","minLength":1},"identifierValue":{"type":"string","minLength":1},"reason":{"type":"string"},"notes":{"type":"string"},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["profileTypeId","identifierType","identifierValue"],"additionalProperties":false}},{"id":"blacklist_entry_remove","name":"blacklist_entry_remove","description":"Permanently delete one blacklist entry by id. Org-scoped: an id belonging to another org matches nothing and is left untouched. After removal the blacklist screener no longer rejects intakes that matched that entry. Returns { ok: true }.","tags":["blacklist"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["id"],"additionalProperties":false}},{"id":"blacklist_entry_import","name":"blacklist_entry_import","description":"Bulk-add blacklist entries for one profile type (the blacklist is PER-PROFILE-TYPE). profileTypeId is REQUIRED. Pass EXACTLY ONE of: `rows` (array of {identifierType, identifierValue, reason?}, up to 5000) OR `csvText` (raw CSV with header `identifier_type,identifier_value,reason`). Every identifierType must be one of that profile type's configured identifiers. Idempotent: entries duplicating an existing (org, profileType, identifierType, identifierValue) are skipped. With `rows` returns { inserted }; with `csvText` returns { totalRows, inserted, skippedDuplicates, rejected: [{ row, reason }] } (bad rows are reported, not fatal; a header mismatch or >5000 rows fails the whole call).","tags":["blacklist"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"profileTypeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"rows":{"minItems":1,"maxItems":5000,"type":"array","items":{"type":"object","properties":{"identifierType":{"type":"string","minLength":1},"identifierValue":{"type":"string","minLength":1},"reason":{"type":"string"}},"required":["identifierType","identifierValue"],"additionalProperties":false}},"csvText":{"type":"string","minLength":1}},"required":["profileTypeId"],"additionalProperties":false}},{"id":"kb_search","name":"kb_search","description":"Semantic search over a knowledge base the caller has access to. orgId + access come from the token. Pass kbId + a query (min 2 chars); limit caps hits (1-50, default 10). Results are filtered to the caller's visibility within the KB.","tags":["kb"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"kbId":{"type":"string"},"query":{"type":"string","minLength":2},"limit":{"default":10,"type":"integer","minimum":1,"maximum":50}},"required":["kbId","query","limit"],"additionalProperties":false}},{"id":"kb_list","name":"kb_list","description":"List the knowledge bases the caller has access to within their org (id, name, description, status).","tags":["kb"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{},"additionalProperties":false}},{"id":"kb_source_status","name":"kb_source_status","description":"Read a single kb_source's ingest status (status + error) by kbId + sourceId. Subject to the same row-visibility predicate as kb_search — a source the caller cannot see is reported as not found.","tags":["kb"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"kbId":{"type":"string"},"sourceId":{"type":"string"}},"required":["kbId","sourceId"],"additionalProperties":false}},{"id":"kb_create","name":"kb_create","description":"Create a new knowledge base in the caller's org (name + optional description). Seeds default grants: org-wide read, customer_admin manage.","tags":["kb"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"name":{"type":"string","minLength":1},"description":{"type":"string"}},"required":["name"],"additionalProperties":false}},{"id":"kb_add_source","name":"kb_add_source","description":"Add a source (document | url | text) to a knowledge base and enqueue durable ingest. document requires fileRef, url requires url, text requires text. External callers must have a resolved buyer/vendor/workflow binding to stamp on the new source — an unbound external caller is rejected.","tags":["kb"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"kbId":{"type":"string"},"type":{"type":"string","enum":["document","url","text"]},"title":{"type":"string"},"text":{"type":"string"},"url":{"type":"string","format":"uri"},"fileRef":{"type":"object","properties":{"_fileRef":{"type":"boolean","const":true},"bucket":{"type":"string"},"key":{"type":"string"},"contentType":{"type":"string"},"size":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["_fileRef","bucket","key","contentType","size"],"additionalProperties":false}},"required":["kbId","type"],"additionalProperties":false}},{"id":"kb_grant_list","name":"kb_grant_list","description":"List the access grants (principalKind, principalId, access) configured on a knowledge base. Requires manage access on the target kbId.","tags":["kb"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"kbId":{"type":"string"}},"required":["kbId"],"additionalProperties":false}},{"id":"kb_grant_add","name":"kb_grant_add","description":"Grant read or manage access to a knowledge base for a principal (org | role | buyer | vendor | workflow | apikey | peer). principalId is required for every kind except 'org' (which must be null). buyer/vendor/workflow principalIds must belong to the caller's org. Requires manage access on the target kbId.","tags":["kb"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"kbId":{"type":"string"},"principalKind":{"type":"string","enum":["org","role","buyer","vendor","workflow","apikey","peer"]},"principalId":{"type":["string","null"]},"access":{"type":"string","enum":["read","manage"]}},"required":["kbId","principalKind","access"],"additionalProperties":false}},{"id":"kb_grant_revoke","name":"kb_grant_revoke","description":"Revoke a knowledge base access grant by grantId. Requires manage access on the target kbId.","tags":["kb"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"kbId":{"type":"string"},"grantId":{"type":"string"}},"required":["kbId","grantId"],"additionalProperties":false}},{"id":"dataset_create","name":"dataset_create","description":"Create an analytical Dataset in the caller's org with a fixed column schema. A Dataset is not the canonical or system-of-record home for facts keyed to a durable governed Profile (for example VIN-keyed vehicle facts); model those as Profiles/Enrichments first. Do not proactively propose a Dataset projection while solving a Profile modeling request; discuss one only after a separate BI/reporting request. A source-backed Profile/Intake/Placement Dataset is only a derived reporting projection of existing governed truth. Pass a unique code, name, optional description, and 1-64 typed columns. By default it is empty and dataset_load supplies rows. Optionally pass `source` as {entity: profiles|intakes|placements, filters?, mapping:[{column,path}]} to materialize a bounded projection immediately; refresh it later with dataset_refresh.","tags":["dataset"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string","pattern":"^[a-z0-9_]{2,64}$"},"name":{"type":"string","minLength":1},"description":{"type":"string"},"columns":{"minItems":1,"maxItems":64,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","pattern":"^[a-z0-9_]{1,64}$"},"type":{"type":"string","enum":["text","number","date","boolean"]},"label":{"type":"string"}},"required":["key","type"],"additionalProperties":false}},"source":{"type":"object","properties":{"entity":{"type":"string","enum":["profiles","intakes","placements"]},"filters":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"mapping":{"minItems":1,"type":"array","items":{"type":"object","properties":{"column":{"type":"string","minLength":1},"path":{"type":"string","minLength":1}},"required":["column","path"],"additionalProperties":false}}},"required":["entity","mapping"],"additionalProperties":false}},"required":["code","name","columns"],"additionalProperties":false}},{"id":"dataset_refresh","name":"dataset_refresh","description":"Re-materialize a source-backed dataset's pipeline slice by code. Only works on datasets created with a `source` (a slice of profiles/intakes/placements); a manually-loaded dataset returns a validation error. Replace semantics: the existing rows are cleared and replaced with the current slice — same 500,000-row cap and atomic all-or-nothing load as dataset_load. This is a point-in-time snapshot, not a live view: widgets show it 'as of' the refresh time. Returns {inserted, rowCount, lastRefreshedAt}. Takes just the dataset code.","tags":["dataset"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string"}},"required":["code"],"additionalProperties":false}},{"id":"dataset_list","name":"dataset_list","description":"List the datasets in the caller's org (code, name, columns, rowCount, lastRefreshedAt), ordered by code. Takes no arguments.","tags":["dataset"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{},"additionalProperties":false}},{"id":"dataset_get","name":"dataset_get","description":"Get one dataset's detail by code: name, description, column schema, rowCount, and lastRefreshedAt. Unknown code (or a code outside the caller's org) is reported as not found.","tags":["dataset"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string"}},"required":["code"],"additionalProperties":false}},{"id":"dataset_load","name":"dataset_load","description":"Bulk-load rows into an existing analytical Dataset by code. This is not a canonical or system-of-record import path for durable Profile entities or their keyed history; a CSV containing VIN/customer/patient/account facts must be classified into Profiles/Enrichments before considering a reporting projection. format:'csv' takes raw content with headers matching column keys; format:'json' takes rows keyed by column. Validation is atomic. mode:'replace' clears existing rows; mode:'append' adds. Caps: 500,000 rows, 8 KB per text cell, and 2 MB inline payload; use POST /api/datasets/{code}/rows for larger files.","tags":["dataset"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string"},"format":{"type":"string","enum":["csv","json"]},"content":{"type":"string"},"rows":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"mode":{"default":"replace","type":"string","enum":["replace","append"]}},"required":["code","format","mode"],"additionalProperties":false}},{"id":"dataset_export","name":"dataset_export","description":"Export a dataset's rows by code. format:'csv' (default) returns a CSV `content` string with a header row; format:'json' returns a `rows` array projected to the declared columns in order. Optional limit/offset page the result (ordered by row id). The response is capped at 1 MB of serialized bytes: if the selection is larger it is truncated to whole rows with truncated:true and a note pointing at GET /api/datasets/{code}/rows for the full export — never a silent cap.","tags":["dataset"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string"},"format":{"default":"csv","type":"string","enum":["csv","json"]},"limit":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"offset":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["code","format"],"additionalProperties":false}},{"id":"dataset_delete","name":"dataset_delete","description":"Delete a dataset by code; its rows are removed with it (ON DELETE CASCADE). Unknown code (or a code outside the caller's org) is reported as not found.","tags":["dataset"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string"}},"required":["code"],"additionalProperties":false}},{"id":"mission_start","name":"mission_start","description":"Launch a durable Mission. Enrichment mode requires a complete immutable enrichment binding and returns a Shape-constrained payload without editing intake data. Preview mode omits enrichmentId. Legacy report Missions remain supported. Missions are read-only by default; poll mission_status for the result.","tags":["mission"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"goal":{"type":"string","minLength":1},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"budget":{"type":"object","properties":{"maxSteps":{"type":"integer","exclusiveMinimum":0,"maximum":64},"maxTokens":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"maxCostCents":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"maxWallMs":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"additionalProperties":false},"allowWrites":{"type":"boolean"}},"required":["goal"],"additionalProperties":false}},{"id":"mission_status","name":"mission_status","description":"Get a Mission by id: its status (queued/running/succeeded/failed/cancelled), the per-step ledger, and the final report/result or error.","tags":["mission"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"missionId":{"type":"string"}},"required":["missionId"],"additionalProperties":false}},{"id":"mission_cancel","name":"mission_cancel","description":"Cancel a running Mission. It stops cleanly at the next step boundary. A finished mission cannot be cancelled.","tags":["mission"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"missionId":{"type":"string"}},"required":["missionId"],"additionalProperties":false}},{"id":"mission_approve","name":"mission_approve","description":"Approve the write/egress action a Mission is currently paused on (status awaiting_approval). The mission resumes and runs the action. Use mission_status to see what it wants to do first.","tags":["mission"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"missionId":{"type":"string"}},"required":["missionId"],"additionalProperties":false}},{"id":"mission_deny","name":"mission_deny","description":"Deny the write/egress action a Mission is paused on. The mission resumes; the model is told the action was denied and continues or ends.","tags":["mission"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"missionId":{"type":"string"}},"required":["missionId"],"additionalProperties":false}},{"id":"bug_report_create","name":"bug_report_create","description":"File a bug report for the platform team. Before calling, gather: a short title, a summary of what happened vs. what was expected, the page it happened on, and any error text shown. The current conversation is attached automatically.","tags":["bug"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"summary":{"type":"string","minLength":1,"maxLength":5000},"pageUrl":{"type":"string","maxLength":500},"errorText":{"type":"string","maxLength":5000}},"required":["title","summary"],"additionalProperties":false}},{"id":"bug_report_close","name":"bug_report_close","description":"Close a bug report in this org with a resolution message. The reporter is emailed the message when they are a known user. Admin only.","tags":["bug"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"id":{"type":"string","minLength":1,"description":"Bug report id (bug-…)"},"resolutionMessage":{"type":"string","minLength":1,"maxLength":5000,"description":"What was done. Emailed to the reporter when they are a known user."}},"required":["id","resolutionMessage"],"additionalProperties":false}},{"id":"buyer_onboard","name":"buyer_onboard","description":"ONE call to onboard a buyer onto a workflow: creates (or updates) the Buyer directory row, optionally sets its delivery config, and adds its routing entry to workflows.placement_shape.routing.buyers[]. Replaces the buyer_create → buyer_delivery_configure → workflow_routing_update_buyer sequence. Idempotent per step; on failure the error names the failed step and what already exists. Returns the buyer id, routing position, and nextSteps naming anything still unmet (delivery unconfigured, live-bid goal unmet).","tags":["buyer"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":80},"name":{"type":"string","minLength":1,"maxLength":200},"billingEmail":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"routing":{"type":"object","properties":{"priority":{"type":"integer","minimum":0,"maximum":9007199254740991},"priceCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string","minLength":3,"maxLength":3},"cap":{"type":"object","properties":{"period":{"type":"string","enum":["day","week","month"]},"limit":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["period","limit"],"additionalProperties":false},"filters":{"type":"object","propertyNames":{"type":"string","minLength":1},"additionalProperties":{}},"pricing":{"type":"string","enum":["live_bid"]}},"required":["priority"],"additionalProperties":false},"delivery":{"type":"object","properties":{"deliveryMode":{"type":"string","enum":["webhook","email","both"]},"deliveryConfig":{"type":"object","properties":{"webhook":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"auth_header":{"description":"Sent verbatim as the Authorization header.","type":"string"},"format":{"description":"Wire format the buyer endpoint requires. json (default) = application/json POST; form = application/x-www-form-urlencoded POST (classic lead-post endpoints like CallShaper /lead/post/<postkey> that reject JSON); query = GET with the mapped fields as query params, no body; raw = POST body_template with content_type (XML, plain text, any custom format).","type":"string","enum":["json","form","query","raw"]},"body_template":{"description":"raw format only — template with {{field}} placeholders resolved against the buyer's mapped payload, e.g. '<lead><phone>{{phone}}</phone></lead>'.","type":"string","maxLength":16384},"content_type":{"description":"raw format only — Content-Type header, default text/plain.","type":"string","maxLength":256}},"required":["url"],"additionalProperties":false},"email":{"type":"object","properties":{"to":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"cc":{"type":"array","items":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}}},"required":["to"],"additionalProperties":false}},"additionalProperties":false}},"required":["deliveryMode","deliveryConfig"],"additionalProperties":false}},"required":["code","name","workflowId","routing"],"additionalProperties":false}},{"id":"vendor_pair","name":"vendor_pair","description":"ONE call to stand up a vendor on a workflow: creates (or updates) the Vendor and attaches it to the workflow. mintKey=true additionally mints the vendor/workflow API key and returns it — THE KEY IS SHOWN ONCE AND NEVER RETRIEVABLE AGAIN; store it immediately. Minting requires a user session (OAuth/desktop callers); api-key callers get the pairing plus a nextSteps note instead. Replaces vendor_create → workflow_vendor_set → manual mint. Idempotent per step; failures name the failed step and what already exists.","tags":["vendor"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":80},"name":{"type":"string","minLength":1,"maxLength":200},"vendorType":{"default":"source","type":"string","enum":["source","enrichment","both"]},"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"mintKey":{"type":"boolean"},"keyLabel":{"type":"string","maxLength":48}},"required":["code","name","vendorType","workflowId"],"additionalProperties":false}},{"id":"buyer_live_bid_enable","name":"buyer_live_bid_enable","description":"ONE call to enable live-bid (RTB) pricing for a buyer on a workflow: saves the bid integration, RUNS ONE REAL TEST CALL (this may cost money at the buyer), extracts the answer's fields, and — when the price field is unambiguous or given as pricePath — records the price goal and flips the routing entry to live_bid. When several numeric fields qualify it returns candidatePaths WITHOUT flipping: the server never guesses which number is the price; call again with pricePath. The buyer must already be on the workflow routing (buyer_onboard first).","tags":["buyer"],"inputModes":["application/json"],"outputModes":["application/json"],"parameters":{"type":"object","properties":{"workflowId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"buyerId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"integration":{"type":"object","properties":{"input":{"type":"object","properties":{"fields":{"default":[],"maxItems":200,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","minLength":1},"kind":{"type":"string","enum":["field","literal"]},"source":{"type":"string"},"transform":{"anyOf":[{"type":"string","enum":["trim","upper","lower","digits","phone10","nospace","yesno","date:YYYY-MM-DD","date:MM/DD/YYYY"]},{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"phone"},"style":{"type":"string","enum":["digits10","e164","pretty","digits"]}},"required":["kind","style"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"pattern":{"type":"string","minLength":1,"maxLength":32}},"required":["kind","pattern"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":200},"replaceWith":{"default":"","type":"string","maxLength":200},"regex":{"default":false,"type":"boolean"},"all":{"default":true,"type":"boolean"},"ignoreCase":{"default":false,"type":"boolean"}},"required":["kind","find","replaceWith","regex","all","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"extract"},"pattern":{"type":"string","minLength":1,"maxLength":200},"group":{"default":0,"type":"integer","minimum":0,"maximum":20}},"required":["kind","pattern","group"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"fallback":{"type":"string"},"ignoreCase":{"default":true,"type":"boolean"}},"required":["kind","values","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"template"},"pattern":{"type":"string","minLength":1,"maxLength":400}},"required":["kind","pattern"],"additionalProperties":false}]}]},"testValue":{"type":"string","maxLength":500}},"required":["key","kind","source"],"additionalProperties":false}}},"required":["fields"],"additionalProperties":false},"tests":{"type":"object","properties":{"pass":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"reject":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["pass","reject"],"additionalProperties":false},"call":{"type":"object","properties":{"endpoint":{"type":"string","format":"uri"},"method":{"default":"POST","type":"string","enum":["GET","POST"]},"format":{"default":"json","type":"string","enum":["json","form","raw"]},"bodyTemplate":{"type":"string","maxLength":16384},"contentType":{"type":"string","maxLength":256},"timeoutMs":{"type":"integer","exclusiveMinimum":0,"maximum":120000},"authMode":{"type":"string","enum":["bearer","basic","raw","none"]},"authHeaderName":{"type":"string","maxLength":128},"headers":{"type":"object","propertyNames":{"type":"string","maxLength":128},"additionalProperties":{"type":"string","maxLength":2048}}},"required":["endpoint","method","format"],"additionalProperties":false},"output":{"default":{"schema":[],"fields":[]},"type":"object","properties":{"schema":{"default":[],"maxItems":200,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1},"path":{"type":"string","minLength":1},"type":{"default":"string","type":"string","enum":["string","number","boolean"]},"seenIn":{"default":"both","type":"string","enum":["pass","reject","both"]}},"required":["name","path","type","seenIn"],"additionalProperties":false}},"fields":{"default":[],"maxItems":200,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","minLength":1},"kind":{"type":"string","enum":["field","literal"]},"source":{"type":"string"},"transform":{"anyOf":[{"type":"string","enum":["trim","upper","lower","digits","phone10","nospace","yesno","date:YYYY-MM-DD","date:MM/DD/YYYY"]},{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"phone"},"style":{"type":"string","enum":["digits10","e164","pretty","digits"]}},"required":["kind","style"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"date"},"pattern":{"type":"string","minLength":1,"maxLength":32}},"required":["kind","pattern"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"replace"},"find":{"type":"string","minLength":1,"maxLength":200},"replaceWith":{"default":"","type":"string","maxLength":200},"regex":{"default":false,"type":"boolean"},"all":{"default":true,"type":"boolean"},"ignoreCase":{"default":false,"type":"boolean"}},"required":["kind","find","replaceWith","regex","all","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"extract"},"pattern":{"type":"string","minLength":1,"maxLength":200},"group":{"default":0,"type":"integer","minimum":0,"maximum":20}},"required":["kind","pattern","group"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"map"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"fallback":{"type":"string"},"ignoreCase":{"default":true,"type":"boolean"}},"required":["kind","values","ignoreCase"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"template"},"pattern":{"type":"string","minLength":1,"maxLength":400}},"required":["kind","pattern"],"additionalProperties":false}]}]},"testValue":{"type":"string","maxLength":500}},"required":["key","kind","source"],"additionalProperties":false}}},"required":["schema","fields"],"additionalProperties":false},"failure":{"default":{"retries":0,"onFailure":"reject"},"type":"object","properties":{"retries":{"default":0,"type":"integer","minimum":0,"maximum":5},"onFailure":{"default":"reject","type":"string","enum":["reject","pass"]}},"required":["retries","onFailure"],"additionalProperties":false},"verdict":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"screener"},"requireWhen":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}},{"oneOf":[{"type":"object","properties":{"op":{"type":"string","const":"equals"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"one_of"},"values":{"type":"array","items":{"type":"string"}}},"required":["op","values"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"between"},"min":{"type":"number"},"max":{"type":"number"}},"required":["op","min","max"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"gte"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"lte"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"gt"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"lt"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"exists"}},"required":["op"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"not_equals"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"contains"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false}]}]}},"rejectWhen":{"default":[],"type":"array","items":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":200},"passReason":{"type":"string","maxLength":200},"match":{"type":"string","enum":["all","any"]},"when":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}},{"oneOf":[{"type":"object","properties":{"op":{"type":"string","const":"equals"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"one_of"},"values":{"type":"array","items":{"type":"string"}}},"required":["op","values"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"between"},"min":{"type":"number"},"max":{"type":"number"}},"required":["op","min","max"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"gte"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"lte"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"gt"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"lt"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"exists"}},"required":["op"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"not_equals"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"contains"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false}]}]}}},"required":["reason","when"],"additionalProperties":false}},"judge":{"default":"reject","type":"string","enum":["pass","reject"]},"mode":{"default":"post","type":"string","enum":["pre_ping","post"]}},"required":["kind","requireWhen","rejectWhen","judge","mode"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"enrichment"}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"buyer"},"acceptWhen":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}},{"oneOf":[{"type":"object","properties":{"op":{"type":"string","const":"equals"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"one_of"},"values":{"type":"array","items":{"type":"string"}}},"required":["op","values"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"between"},"min":{"type":"number"},"max":{"type":"number"}},"required":["op","min","max"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"gte"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"lte"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"gt"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"lt"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"exists"}},"required":["op"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"not_equals"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"contains"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false}]}]}},"failureBodyPattern":{"type":"string","maxLength":500}},"required":["kind"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","const":"action"},"succeedWhen":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}},{"oneOf":[{"type":"object","properties":{"op":{"type":"string","const":"equals"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"one_of"},"values":{"type":"array","items":{"type":"string"}}},"required":["op","values"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"between"},"min":{"type":"number"},"max":{"type":"number"}},"required":["op","min","max"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"gte"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"lte"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"gt"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"lt"},"value":{"type":"number"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"exists"}},"required":["op"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"not_equals"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false},{"type":"object","properties":{"op":{"type":"string","const":"contains"},"value":{"type":"string"}},"required":["op","value"],"additionalProperties":false}]}]}}},"required":["kind"],"additionalProperties":false}]}},"required":["input","output","failure","verdict"],"additionalProperties":false},"secret":{"type":"string","maxLength":4096},"testSample":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"pricePath":{"type":"string","minLength":1}},"required":["workflowId","buyerId","integration","testSample"],"additionalProperties":false}}]}